Как вы думаете, «правильный результат»? Я предполагаю, что вы верите, что это 34032,1. Это не так.
2.1 не представляется как float
, поэтому val_f
вместо этого инициализируется с ближайшим представимым значением float
. В двоичном коде 2.1 это:
10.000110011001100110011001100110011001100110011001...
a float
имеет 24 двоичных разряда, поэтому значение val_f
в двоичном виде:
10.0001100110011001100110
Выражение resultat = val_c + val_i + val_l + val_f
вычисляет 34030 + val_f
, которое вычисляется с одинарной точностью и вызывает другое округление.
1000010011101110.0
+ 10.0001100110011001100110
-----------------------------------------
1000010011110000.0001100110011001100110
rounds to 24 digits:
-----------------------------------------
1000010011110000.00011010
В десятичном виде этот результат в точности равен 34032.1015625. Поскольку формат %f
печатает 6 цифр после десятичной точки (если не указано иное), он снова округляется, и printf печатает 34032.101562
.
Теперь, почему вы не получаете этот результат при компиляции с MSVC? Стандарты C и C ++ позволяют выполнять вычисления с плавающей точкой в более широком типе, если компилятор решит это сделать. MSVC делает это с вашими вычислениями, что означает, что результат 34030 + val_f
не округляется перед передачей в printf
. В этом случае точное значение с плавающей точкой для печати равно 34032.099999999991268850862979888916015625, которое округляется до 34032.1 с помощью printf.
Почему не все компиляторы делают то, что делает MSVC? Несколько причин. Во-первых, это медленнее на некоторых процессорах. Во-вторых, и что более важно, хотя он может дать более точные ответы, программист не может зависеть от этого - казалось бы, несвязанные изменения кода могут вызвать изменение ответа при наличии такого поведения. Из-за этого дополнительная точность часто вызывает больше проблем, чем решает.