Как работает целочисленное деление в C ++ для предельных и отрицательных значений?

Я сталкиваюсь с некоторыми странными результатами с целочисленным делением в C ++. Я пытаюсь рассчитать это: -2147483648 / -1.

Я получаю 3 разных результата в 3 разных сценариях:

int foo(int numerator, int denominator) {
int res = numerator / denominator; // produces SIGFPE, Arithmetic exception interrupt

cout << res << endl;
}

int main() {
int res = -2147483648 / -1;
cout << res << endl;               // prints -2147483648
cout << -2147483648 / -1 << endl;  // prints 2147483648
foo(-2147483648, -1);
return 0;
}

Почему целочисленная операция деления дает разные результаты в разных ситуациях?

14

Решение

Буквальный -2147483648 / -1 рассчитывается вашим компилятором как 2147483648 в типе данных, который достаточно широк, чтобы содержать это значение.

Когда литерал распечатывается напрямую, он печатает значение правильно.

Когда литерал хранится в resэто брошено на int, int кажется, в вашей системе 32 бит в ширину. Значение 2147483648 не может быть представлен как 32-битное целое число со знаком, поэтому приведение вызывает переполнение. В вашей системе это переполнение приводит к значению -2147483648 (вероятно, он использует два дополнения).

Наконец, при попытке выполнить деление во время выполнения (в foo функция), то SIGFPE исключение происходит из-за переполнения (потому что int тип данных не может представлять результат).

Обратите внимание, что все эти три параметра зависят от поведения платформы:

  • тот факт, что компилятор не генерирует никаких ошибок (или других проблем) при переполнении литерального вычисления, а просто использует тип данных, достаточно большой для хранения результата
  • тот факт, что int переполнение при хранении литерала генерирует это конкретное значение (и никаких других проблем)
  • тот факт, что SIGFPE исключение выдается при переполнении во время выполнения
12

Другие решения

Ваш результат может быть INT_MAX+1другими словами, это вероятно переполняется. Это неопределенное поведение, и все может случиться. Например, компилятор может отклонить код напрямую.

(Система может иметь INT_MAX >= 2147483648, но тогда вы ожидаете того же результата для ваших 3 тестовых случаев)

12

int res = -2147483648 / -1;
cout << res << endl;               // prints -2147483648
cout << -2147483648 / -1 << endl;  // prints 2147483648
int res = numerator / denominator; // produces SIGFPE, Arithmetic exception interrupt

Обратите внимание, что нет никаких отрицательных целочисленные литералы.

Там нет отрицательных целочисленных литералов. Такие выражения, как -1, применяют унарный оператор минус к значению, представленному литералом, что может включать неявные преобразования типов.

Буквальный 2147483648 больше, чем максимальное значение intтак что его тип будет long (или же long long, зависит от реализации). затем -2147483648 тип longи результат расчета (-2147483648 / -1) является long тоже.

Для 1-го случая результат 2147483648 типа long является неявно преобразуется в int, но это больше, чем максимальное значение intрезультат определяется реализацией. (Кажется, что результат оборачивается в соответствии с правилами представления (дополнение 2) здесь, так что вы получите результат -2147483648.)

Для 2-го случая результат с типом long распечатывается напрямую, поэтому вы получите правильный результат.

Для третьего случая вы делаете расчет на двух ints, и результат не может вписаться в тип результата (т.е. int), переполнение целочисленной арифметической операции со знаком случилось, поведение не определено. (Создает SIGFPE, прерывание арифметического исключения здесь.)

10
По вопросам рекламы [email protected]