Модуль переполнен?
Я знаю, что (INT_MIN / -1) переполняется, но (INT_MIN % -1) нет. По крайней мере, это то, что происходит в двух компиляторах, один до C++11 (VC++ 2010) и другой после C++11 GCC 4.8.1
int x = INT_MIN;
cout << x / -1 << endl;
cout << x % -1 << endl;
дает:
-2147483648
0
Определен ли этот стандарт поведения или это определяется реализацией? Также есть ЛЮБОЙ ДРУГОЙ случай, когда операция деления была бы переполнена? и есть ли случай, когда оператор модуля будет переполнен?
3 ответа
Согласно стандарту CERT C++ Secure Coding Standard модуль может переполниться следующим образом:
[...] Переполнение может происходить во время операции по модулю, когда дивиденд равен минимальному (отрицательному) значению для целочисленного типа со знаком, а делитель равен -1.
и они рекомендуют следующий стиль проверки для предотвращения переполнения:
signed long sl1, sl2, result;
/* Initialize sl1 and sl2 */
if ( (sl2 == 0 ) || ( (sl1 == LONG_MIN) && (sl2 == -1) ) ) {
/* handle error condition */
}
else {
result = sl1 % sl2;
}
Проект стандарта C++ 5.6
Мультипликативные операторы параграф 4 говорит (выделение мое):
Двоичный / оператор дает частное, а двоичный оператор% - остаток от деления первого выражения на второе. Если второй операнд / или% равен нулю, поведение не определено. Для целочисленных операндов оператор / дает алгебраический фактор с любой отброшенной дробной частью; 81, если частное a/b представимо в типе результата, (a/b)*b + a%b равно a; в противном случае поведение как a/b, так и% b не определено.
C-версия документа CERT дает более глубокое понимание того, как %
работает на некоторых платформах, а в некоторых случаях INT_MIN % -1
может произвести исключение с плавающей точкой.
Логика предотвращения переполнения для / такая же, как и вышеупомянутая логика для %
,
Это не операция по модулю, которая вызывает переполнение:
int x = INT_MIN;
int a = x / -1; // int's are 2's complement, so this is effectively -INT_MIN which overflows
int b = x % -1; // there is never a non-0 result for a anything +/- 1 as there is no remainder
Каждая современная реализация языка C++ использует два дополнения в качестве базовой схемы представления целых чисел. В результате, -INT_MIN никогда не может быть представлен как int. (INT_MAX - это -1+INT_MIN). Это переполнение, потому что значение x/-1 не может быть представлено как int, если x равно INT_MIN.
Подумайте о том, что% вычисляет. Если результат может быть представлен как int, переполнения не будет.