double сохраняет данные не в точном виде. Нужен ли тип данных, который будет сохранять все знаки после запятой в точном виде?

 

Числа double хранятся в памяти компьютера с ограниченной точностью.

Пример:

0.7000000000000001 вместо 0.7

0.0999999999999999 вместо 0.1



В некоторых языках программирования есть тип данных DECIMAL.



 
multiplicator:

"Каждый из нас сталкивался с выводом в строку чисел вида 3,4999990123 вместо 3,5 или, того хуже, огромной разницей после вычислений между результатом теоретическим и тем, что получилось в результате выполнения программного кода."

В некоторых языках программирования есть тип данных DECIMEL.

Скачать видео



Скачать видео

Тип Decimal есть во всех вменяемых БД, а как еще прикажете хранить денежные величины? Ну не в double же. Странно, что в MQL, который заточен на работу с финансами, такого типа нет. Проголосовал Да.

Попутно родилась мысль сделать сласс CDecimal ))

 
multiplicator:

"Каждый из нас сталкивался с выводом в строку чисел вида 3,4999990123 вместо 3,5 

Я не сталкивался:

double d=3.5;
Print(DoubleToString(d,10)); // результат - 3.5000000000

double - очень грамотный тип данных

И если знать и понимать его устройство, то проблем в сравнения двух double-чисел не будет.

Приведите конкретный пример, который заводит Вас в тупик. Я найду Вам решение.

 
Nikolai Semko:

Я не сталкивался:

Надеюсь, следущий код не вызовет баттхерт ))

//http://lurkmore.to/Butthurt

    double d=3.5;
    double d2 = 0.9999995555999999999999999999999999999999999999999999999;
    d *= d2;
    d /= d2;
    Print(DoubleToString(d,19)); // результат - 2018.12.02 06:37:42.368 TestDouble (EURUSD,M5)  3.5000000000000001

 
Nikolai Semko:

Я не сталкивался:

double - очень грамотный тип данных

И если знать и понимать его устройство, то проблем в сравнения двух double-чисел не будет.

Приведите конкретный пример, который заводит Вас в тупик. Я найду Вам решение.

Чего там грамотного-то? Даже древний формат сопроцессора длиной 80 бит, который был еще в Intel 8087 не поддерживает, только 64 бита. Для финансовых расчетов double нигде не применяется.

 
Alexey Volchanskiy:

Чего там грамотного-то? Даже древний формат сопроцессора длиной 80 бит, который был еще в Intel 8087 не поддерживает, только 64 бита. Для финансовых расчетов double нигде не применяется.

А кто заставляет финансы в double считать? Считайте в long, предварительно избавившись от запятой умножением на порядок нужной точности. 

В процессорах, между прочим, тип double реализован на уровне железа. Компании Intel и AMD дебилы что-ли?

 
Alexey Volchanskiy:

Надеюсь, следущий код не вызовет баттхерт ))

и в чем тут проблема?

Что? Важен 16 знак после запятой в типе, в котором точность заканчивается на 16-м знаке?

 
Nikolai Semko:

Я не сталкивался:

   double pi=M_PI;
   Print("pi=",DoubleToString(pi,16));
      
   double pi_3=NormalizeDouble(M_PI,3);
   Print("NormalizeDouble(pi,3) = ",DoubleToString(pi_3,16))
   ;
   double pi_8=NormalizeDouble(M_PI,8);
   Print("NormalizeDouble(pi,8) = ",DoubleToString(pi_8,16));
   
   double pi_0=NormalizeDouble(M_PI,0);
   Print("NormalizeDouble(pi,0) = ",DoubleToString(pi_0,16));
/*
   Результат:
   pi= 3.1415926535897931
   NormalizeDouble(pi,3)= 3.1419999999999999
   NormalizeDouble(pi,8)= 3.1415926499999998
   NormalizeDouble(pi,0)= 3.0000000000000000
*/
 
multiplicator:

да, все правильно. 
В чем проблема то?

Вас раздражают девятки? Меня нет, т.к. я понимаю как устроен тип double.
Все верно, можете проверить:

if (3.1419999999999999 == 3.142) Print("Ok");
if (3.1415926499999999 == 3.14159265) Print("Ok");

Кстати, функция NormalizeDouble в MQL5 работает не совсем корректно, но тип double здесь не причем.

Правильное значение от NormalizeDouble(M_PI,8) = 3.1415926500000002 , а не 3.1415926499999998

это можно проверить в альтернативном варианте fxsabera здесь или моем варианте здесь


 
Задача:
Приходит человек в магазин. Конфета стоит 0,1 доллара. Он покупает ее. Следующая конфета стоит 0,2 доллара. Следующая 0,3 доллара.
каждая последующая конфета стоит на 0,1 доллара дороже.
Он закончит покупать конфеты, когда у него уже не будет денег для покупки следующей конфеты.

Написать код и в конце вывести алерт, сколько у него осталось денег.

Посчитаем в уме: 0,1+0,2+0,3+0,4. Должно остаться 0 денег.

Напишем код с использованием чисел double:
double funds=1;
int itemsBought=0;

for (double price=0.1; funds>=price; price+=0.1)
{
funds-=price;
itemsBought++;
}

Alert(itemsBought);
Alert(funds);

Результат: 0.3999999999999999

вот такие ошибки могут появляться из-за ограниченной точности.



оригинал:


Причина обращения: