Почему 0.1 + 0.2 == 0.3 в D?

assert(0.1 + 0.2 != 0.3); // shall be true

- моя любимая проверка того, что язык использует собственную арифметику с плавающей запятой.

С++

#include <cstdio>

int main()
{
   printf("%d\n", (0.1 + 0.2 != 0.3));
   return 0;
}

Вывод:

1

http://ideone.com/ErBMd

Python

print(0.1 + 0.2 != 0.3)

Вывод:

True

http://ideone.com/TuKsd

Другие примеры

Почему это не так для D? Понятно, что D использует собственные числа с плавающей запятой. Это ошибка? Используют ли они какое-то определенное числовое представление? Что-то другое? Довольно запутанный.

D

import std.stdio;

void main()
{
   writeln(0.1 + 0.2 != 0.3);
}

Вывод:

false

http://ideone.com/mX6zF

UPDATE

Благодаря LukeH. Это эффект Floating Point Constant Folding, описанный там.

код:

import std.stdio;

void main()
{
   writeln(0.1 + 0.2 != 0.3); // constant folding is done in real precision

   auto a = 0.1;
   auto b = 0.2;
   writeln(a + b != 0.3);     // standard calculation in double precision
}

Вывод:

false
true

http://ideone.com/z6ZLk

Ответ 1

Вероятно, он оптимизирован до (0,3!= 0,3). Это, очевидно, ложно. Проверьте настройки оптимизации, убедитесь, что они выключены, и повторите попытку.

Ответ 2

(Ответ Flynn - правильный ответ. В этом случае проблема решается чаще).


Похоже, вы предполагаете, OP, что неточность с плавающей запятой в вашем коде детерминирована и предсказуема неправильно (в некотором смысле, ваш подход является полярным, противоположным тому, который не понимает с плавающей точкой).

Хотя (как указывает Бен), неточность с плавающей запятой является детерминированной, с точки зрения вашего кода, если вы не очень преднамеренно о том, что происходит с вашими значениями на каждом шагу, это не так. Любое количество факторов может привести к следующему 0.1 + 0.2 == 0.3, оптимизация времени компиляции - это одно, повышенные значения для тех литералов, которые являются другими.

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

Ответ 3

Согласно моей интерпретации спецификации языка D, арифметика с плавающей запятой на x86 будет использовать внутри себя 80 бит точности, а не только 64 бита.

Однако нужно было бы проверить, что этого достаточно, чтобы объяснить результат, который вы наблюдаете.