Сравнение double и float - неявное приведение - PullRequest
4 голосов
/ 28 января 2020

Предположим, у нас есть переменные double d и float f на языке программирования C.

Насколько я понимаю, выражение d == (float) d не будет истинным для всех двойных значений, поскольку, когда мы бросаем его на плаву, мы его усекаем и, следовательно, теряем точность.

С другой стороны, f == (double) f должно быть истинным для всех значений с плавающей запятой (кроме NaN, потому что это NaN! = NaN), поскольку мы ничего не теряем (просто расширяем мантиссу нулями).

Я читал, что при сравнении числа с плавающей точкой число с плавающей точкой неявно будет приведено к двойному: https://en.cppreference.com/w/c/language/conversion#Usual_arithmetic_conversions, верно ли это неявное приведение ко всем значениям (включая бесконечность и NaN)?

Я знаю, что это довольно простой вопрос; Я играл с ним некоторое время, но было бы здорово, если бы кто-то смог это подтвердить. На первую часть уже даны ответы в других сообщениях, но я не нашел ответов на вторую часть вопроса.

Ответы [ 2 ]

2 голосов
/ 28 января 2020

В реализации C, соответствующей стандарту C, f == (double) f оценивается как истинное для всех float значений f, кроме NaN. (Для NaN f == f является ложным.) Это верно, потому что в f == (double) f левый операнд равен float, поэтому он автоматически преобразуется в double, а выражение тогда эквивалентно (double) f == (double) f и т. д. по своей сути верно.

Стандарт C позволяет реализациям оценивать выражения с плавающей точкой с большей точностью, чем номинальные типы операндов. Однако избыточная точность не будет влиять на операторы приведения (которые необходимы для сброса избыточной точности) или оператор ==. Поэтому на (double) f == (double) f это не влияет, и его вычисленное значение совпадает с его математическим значением.

Вас может заинтересовать результат f == (float) (double) f. При этом, поскольку оба операнда == имеют тип float, автоматическое преобразование c в double отсутствует. Вы можете спросить, вводит ли преобразование в double какое-то изменение, а затем преобразование обратно в float может привести к другому значению. Он не может.

Чтобы увидеть, что он не может, подумайте, является ли f бесконечностью. Тогда (double) f - это бесконечность, как и (float) (double) f, поэтому результатом является сравнение бесконечности с бесконечностью, которое оценивается как истинное. (Это также верно для отрицательной бесконечности.) Если f не является бесконечностью или NaN, это конечное значение.

Per C 2018 6.2.5 10, «Набор значений типа float является подмножеством набора значений типа double;… ». Следовательно, каждое значение, представляемое в float, представимо в double, поэтому преобразование в double не меняет значение, и и при этом преобразование не возвращается к float. Следовательно, f == (float) (double) f оценивается как true для всех float значений f, кроме NaN.

Обратите внимание, что, хотя вы не можете определить, являются ли два NaN идентичными, с помощью ==, вы можете сравнить байты в их представления с использованием memcmp. В этом случае преобразование в double и обратно в float не требуется для сохранения какой-либо информации в объекте NaN, кроме того, что это NaN; любая информация полезной нагрузки может быть потеряна.

1 голос
/ 28 января 2020

Да. Приведение с большей точностью не даст неправильных значений, и это правда, что сравнение float с double неявно приведёт float к double.

...