Я сталкиваюсь с некоторыми странными результатами с целочисленным делением в 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;
}
Почему целочисленная операция деления дает разные результаты в разных ситуациях?
Буквальный -2147483648 / -1
рассчитывается вашим компилятором как 2147483648
в типе данных, который достаточно широк, чтобы содержать это значение.
Когда литерал распечатывается напрямую, он печатает значение правильно.
Когда литерал хранится в res
это брошено на int
, int
кажется, в вашей системе 32 бит в ширину. Значение 2147483648
не может быть представлен как 32-битное целое число со знаком, поэтому приведение вызывает переполнение. В вашей системе это переполнение приводит к значению -2147483648
(вероятно, он использует два дополнения).
Наконец, при попытке выполнить деление во время выполнения (в foo
функция), то SIGFPE
исключение происходит из-за переполнения (потому что int
тип данных не может представлять результат).
Обратите внимание, что все эти три параметра зависят от поведения платформы:
int
переполнение при хранении литерала генерирует это конкретное значение (и никаких других проблем)SIGFPE
исключение выдается при переполнении во время выполненияВаш результат может быть INT_MAX+1
другими словами, это вероятно переполняется. Это неопределенное поведение, и все может случиться. Например, компилятор может отклонить код напрямую.
(Система может иметь INT_MAX >= 2147483648
, но тогда вы ожидаете того же результата для ваших 3 тестовых случаев)
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
распечатывается напрямую, поэтому вы получите правильный результат.
Для третьего случая вы делаете расчет на двух int
s, и результат не может вписаться в тип результата (т.е. int
), переполнение целочисленной арифметической операции со знаком случилось, поведение не определено. (Создает SIGFPE, прерывание арифметического исключения здесь.)