Предположительно, вы запускаете эту программу на процессоре Intel. (Задавая подобные вопросы, вы всегда должны указывать, какой компилятор вы используете, включая версию и параметры командной строки, а также на какой системе вы запускаете программу.) Процессоры Intel имеют 80-битный формат с плавающей запятой, которыйимеет 64-битные значения. (Значение и является дробной частью числа с плавающей запятой.)
Похоже, что ваш компилятор использует 80-битный формат с плавающей запятой процессора для промежуточных вычислений, и он, вероятно, использует базовый IEEE-75464-битный двоичный формат для double
. Стандарт C позволяет реализациям C оценивать выражения с плавающей точкой с большей дальностью и точностью, чем номинальный тип. Это означает, что когда компилятор оценивает (или генерирует код для оценки) выражение double
, ему разрешается использовать 80-битный тип.
Когда объекту присваивается выражение с плавающей запятой илиСуществует явное приведение к типу с плавающей точкой, стандарт C требует, чтобы реализация C «отбрасывала» избыточную точность.
Вышеприведенное позволяет нам увидеть, что произошло. 1e20
представляет 10 20 , что является числом от 2 66 до 2 67 . Записанный в двоичном виде, его ведущий бит находится в позиции для значения 2 66 . Поскольку 80-битный формат имеет 64-битные значения, наименее значимый бит, который может быть представлен в формате, находится в позиции 2 3 (число битов от 3 до 66 равно 64 битам). После b = 1e20
, когда вы добавляете 5 к b
, результат должен быть округлен до битов от 2 66 до 2 3 (что равно 8). Это приводит к округлению числа до следующего, кратного 8. Таким образом, из-за округления, b+5
имеет тот же результат, что и b+8
. Затем, когда вы добавляете c
, что равно -b
, вы получаете 8.
В double temp = a+b;
, назначение заставляет реализацию C «отбрасывать» избыточную точность. Таким образом, он должен преобразовать результат в формат double
, который имеет 53-битные значения. С начальным битом 2 66 младший бит равен 2 14 . Биты от 2 13 до 2 3 отбрасываются, а оставшиеся биты округляются (что не приводит к каким-либо изменениям в этом случае, поскольку отброшенные биты оказываются меньше, чемсредняя точка). Таким образом, хотя a+b
равно b+8
, как мы видели выше, результат преобразования b+8
в double
равен просто b
. Затем, добавив c
к этому, вы получите 0.