Модуль переполнен?

Я знаю, что (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, переполнения не будет.

Другие вопросы по тегам