Переполнение после неявного приведения
Когда я пытаюсь сделать неявное преобразование из Double в длинное целое без знака, у меня переполнение предупреждение : "предупреждение: переполнение при неявном преобразовании константы [-Woverflow]".
Вот инструкция:
unsigned long ulongMax = pow(2.0, 64.0) - 1;
Но когда я явно бросаю это, как показано ниже, это нормально !
unsigned long ulongMax = (unsigned long) (pow(2.0, 64.0) - 1);
Я не понимаю, почему у меня есть предупреждение, результат (18446744073709551615) такой же, как ULONG_MAX
из заголовка "limits.ч".
3 ответа:
pow(2.0, 64.0)
возвращает adouble
.Однако (предполагая нормальную систему IEEE754), значения
pow(2.0, 64.0)
иpow(2.0, 64.0) - 1
фактически равны. Это происходит потому, что мы находимся вне диапазона, где соседние целые числа точно представимы вdouble
. (Конечно, 64-битный двойник не может представлять все 64-битные целые числа).Теперь, вне диапазона приведения от плавающей точки к целочисленному типу вызываетнеопределенное поведение , без необходимости диагностики.
Ваш компилятор пытается быть полезным с помощью предупреждая вас об этом неопределенном поведении в первом случае, но (предположительно) он рассматривает добавление актерского состава как сообщение от вас: "я не хочу слышать это предупреждение".
Предупреждение означает, что оно потенциально может потерять точность, если
pow(2.0, 64.0) - 1
будет слишком большим или с дробной частью (скажем, 1.7*10^308, что является максимальным для двойников) или 0.9, что будет усечено до 0).Причина, по которой вы не получаете предупреждение при использовании явного приведения
(unsigned long) (pow(2.0, 64.0) - 1)
, заключается в том, что будучи явным, вы говорите: "Я на самом деле хочу получить unsigned long от этого двойника (независимо от неприятных последствий этого)"
Наиболее вероятная причина, по которой вы получаете предупреждение, заключается в том, что
unsigned long
на вашей платформе 32-битный, а не 64-битный размер.Если вы переключитесь на 64-битный unsigned, предупреждение исчезнет:
unsigned long long ulongMax = pow(2.0, 64.0) - 1; printf("%llu", ulongMax);
Явное приведение устраняет предупреждение, потому что по существу оно сообщает компилятору, что вы знаете о том, что происходит, и вы хотите, чтобы он был спокоен и делал так, как вы говорите.