В реализации 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; любая информация полезной нагрузки может быть потеряна.