Пожалуйста, объясните, почему первый фрагмент кода не дает -1.

    string s = "abc";
    int amount = -1;
    cout << "amount to shift before modulus: " << amount<<endl;
    amount %= s.size();
    cout << "mod " <<s.size()<<endl;
    cout << "amount to shift after modulus: " << amount<<endl;

Вывод:
величина сдвига перед модулем: -1
мод 3
количество сдвига после модуля: 0

    string s = "abc";
    int sSize = s.size();
    int amount = -1;
    cout << "amount to shift before modulus: " << amount<<endl;
    amount %= sSize;
    cout << "mod " <<sSize<<endl;
    cout << "amount to shift after modulus: " << amount<<endl;

Вывод:
величина сдвига перед модулем: -1
мод 3
количество сдвига после модуля: -1

Я выполнял задачу по кодированию, когда столкнулся с таким поведением, и я не понимаю, что происходит. Этого не происходит, если сумма является положительным числом, например 1.

1
Calamari 15 Апр 2020 в 04:50

1 ответ

Лучший ответ

Если вы выполняете арифметические действия (включая арифметическое сравнение) между целым числом со знаком и целым числом без знака, а тип целого числа без знака имеет ширину не менее целого числа со знаком, то целое число со знаком преобразуется в целое число без знака . (Это результат так называемых «обычных арифметических преобразований». )

Это почти всегда дает неожиданные результаты, если только арифметическая операция не является сложением или вычитанием. Во многих случаях хороший компилятор предупредит вас о выполнении арифметики со смешанными знаками, если вы запросите предупреждения. (Настоятельно рекомендуется!) Это лишь один относительно необычный вариант.

В первом случае s.size() имеет тип size_t, который является беззнаковым типом, вероятно, 64-битным; следовательно, он шире, чем int. Итак, чтобы вычислить amount % s.size(), компилятор сначала преобразует amount в беззнаковый size_t, что приведет к 2 64 -1. Оказывается, это число делится на 3, поэтому операция по модулю возвращает 0.

Во втором случае вы принудительно преобразовываете s.size() в целое число со знаком. Поскольку значение определенно находится в пределах int, преобразование четко определено. Последующая операция по модулю выполняется для подписанных int s и дает ожидаемый результат, если вы ожидаете, что подписанный модуль будет работать так же, как в C ++. (См. Почему C ++ выводит отрицательные числа при использовании по модулю? для получения дополнительной информации.)

4
rici 15 Апр 2020 в 02:25