Является ли numeric_limits <int> :: is_modulo логически противоречивым?
ВДругой вопростемаstd::numeric_limits<int>::is_modulo
подошел. Но чем больше я думаю об этом, тем больше кажется, что что-то не так со спецификацией, с GCC или с обоими.
Позвольте мне начать с некоторого кода:
#include <limits>
#include <iostream>
bool test(int x)
{
return x+1 > x;
}
int main(int argc, char *argv[])
{
int big = std::numeric_limits<int>::max();
std::cout << std::numeric_limits<int>::is_modulo << " ";
std::cout << big+1 << " ";
std::cout << test(big) << "\n";
}
Когда я собираю это сg++ -O3 -std=c++11
(x86_64 GCC 4.7.2), он производит следующий вывод:
1 -2147483648 1
Это,is_modulo
верно, один плюсINT_MAX
отрицательно, и один плюсINT_MAX
больше, чемINT_MAX
.
Если вы из тех людей, у которых есть реальная возможность ответить на этот вопрос, вы уже знаете, что здесь произошло. Спецификация C ++ говорит, что целочисленное переполнение - Неопределенное Поведение; компилятор может предположить, что вы этого не делаете; поэтому аргументx+1
не может бытьINT_MAX
; поэтому компилятор может (и будет) компилироватьtest
функция для возвратаtrue
безусловно. Все идет нормально.
ОднакоC ++ 11 spec также говорится (18.3.2.4 параграфы 60-61):
static constexpr is_modulo;
Истинно, если тип является модулем. 222 Тип является модулем, если для любой операции, включающей+
, -
, или же*
на значениях этого типа, результат которых выходит за пределы диапазона[min(),max()]
возвращаемое значение отличается от истинного значения на целое число, кратноеmax() - min() + 1
.
На большинстве машин этоfalse
для плавающих типов,true
для целых чисел без знака иtrue
для целых чисел со знаком.
Обратите внимание, что параграф (4) раздела 5 по-прежнему гласит: «Если во время вычисления выражения результат не определен математически или не находится в диапазоне представимых значений для его типа, поведение не определено». Там нет упоминания оis_modulo == true
создавая исключение
Поэтому мне кажется, что стандарт логически противоречив, потому что целочисленное переполнение не может быть одновременно определено и не определено. Или, по крайней мере, GCC не соответствует, потому что он имеетis_modulo
какtrue
хотя подписанная арифметика наверняка не оборачивается.
Стандартный глючит? GCC не соответствует? Я что-то пропустил?