Стандарт позволяет вычислять числа с плавающей точкой с большей точностью, чем тип выражения;например:
float f = 1.234f * 5.678f;
Компилятору разрешено преобразовывать операнды в long double
, выполнять умножение, а затем преобразовывать обратно в float
.Основанием для этого является то, что на многих процессорах быстрее просто использовать определенный размер регистра с плавающей запятой для вычислений, и обычно люди не заботятся о получении точности.
Это указано в C17 5.2.4.2.2 / 9:
За исключением присваивания и приведения (которые удаляют весь дополнительный диапазон и точность), значения, получаемые операторами с плавающей точкойОперанды и значения, подверженные обычным арифметическим преобразованиям и плавающим константам, оцениваются в формате, диапазон и точность которого могут быть больше, чем требуется типом.Использование форматов оценки характеризуется значением, определяемым реализацией FLT_EVAL_METHOD
:
−1
не определимо; 0
оценивает все операции и константы только для диапазонаи точность типа; 1
оценивают операции и константы типа float и double для диапазона и точности типа double, оценивают длинные двойные операции и константы для диапазона и точности типа long double; 2
вычисляет все операции и константы для диапазона и точности типа long double.
Все остальные отрицательные значения для FLT_EVAL_METHOD
характеризуют поведение, определяемое реализацией.
Таким образом, вы можете проверить FLT_EVAL_METHOD
, чтобы выяснить, может ли компилятор сделать это, но вы не можете самостоятельно контролировать настройку.
Текст, который вы цитируете,подтверждая, что оператор приведения преобразует результат обратно в тип приведения, например:
float f = 1.234f * 5.678f + 9.012f;
теоретически может дать болееТочный результат, чем:
float f = (float)(1.234f * 5.678f) + 9.012f;