Переполнение после неявного приведения


Когда я пытаюсь сделать неявное преобразование из 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 3

3 ответа:

pow(2.0, 64.0) возвращает a double.

Однако (предполагая нормальную систему 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);

Демо.

Явное приведение устраняет предупреждение, потому что по существу оно сообщает компилятору, что вы знаете о том, что происходит, и вы хотите, чтобы он был спокоен и делал так, как вы говорите.