WTF? MathMod(1.01,0.001) == 0.001??? - страница 2

 

Тоже запарился с этой функцией...

Работает не стабильно верно.

Пришлось в итоге свою писать, т.е. вычитать в цикле.
 
Maxim Kuznetsov:

потому что 1.01  не представляется в точности, double ..

образно: оно для компьютера 1.009(9) , соотв целая часть от x/0.001 получается 100  и остаток (модуль) 0.0009(9) который приводится к 0.001

c double надо быть крайне осторожным из-за подобных вещей и всегда про них помнить

С такими рассуждениями надо в банке работать ;)


По факту, система работающая с финансовыми активами должна оперировать десятичными числами без ошибок.

На всякий случай скажу, что кроме double и float человечество придумало другие форматы для храния рациональных чисел. Например, BCD (binary-coded decimal)

 
Alexey Viktorov:

.

Соответственно, вещественный остаток, это остаток в виде вещественного числа.

У тебя тоже гугол работает? Как твой ответ решил вопрос этой ветки??? Не знаешь, не флуди.

 

Я решил так, но не до хренали костылей в mql.)))

//Остаток от деления
double fMod(double x,double y){
   if(y == 0){
      Print(__FUNCTION__," Division by zero!");
      return 0;
   }
   double z = NormalizeDouble(x/y,8);
   return z-int(z);
}
 
Mikhail Nazarenko:

Я решил так, но не до хренали костылей в mql.)))

норм

получить один верный ответ этой функции не есть норм

надо за ней присматривать

 
Mikhail Nazarenko:

Я решил так, но не до хренали костылей в mql.)))

глупости какие то пишете

есть вещественный остаток от деления вещественных чисел https://www.mql5.com/ru/docs/math/mathmod

есть целочисленный остаток от деления целых чисел https://www.mql5.com/ru/docs/basis/operations/mathoperation


если у Вас разные типы данных - делитель и делимое, то нужно самостоятельно преобразовать к одному типу или разобраться с приведением типов https://www.mql5.com/ru/docs/basis/types/casting

 
Igor Makanu:


если у Вас разные типы данных - делитель и делимое

У него данные одного типа

 
Igor Makanu:

глупости какие то пишете

есть вещественный остаток от деления вещественных чисел https://www.mql5.com/ru/docs/math/mathmod

есть целочисленный остаток от деления целых чисел https://www.mql5.com/ru/docs/basis/operations/mathoperation


если у Вас разные типы данных - делитель и делимое, то нужно самостоятельно преобразовать к одному типу или разобраться с приведением типов https://www.mql5.com/ru/docs/basis/types/casting

В самом начале читаем суть ветки, потом даем рекомендации. Главное не перепутать.)

 
Mikhail Nazarenko:

В самом начале читаем суть ветки, потом даем рекомендации. Главное не перепутать.)

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

WTF? MathMod(1.01,0.001) == 0.001???

Mikhail Nazarenko, 2021.06.02 17:08

Столкнулся в MT5. MathMod(1.01,0.001) == 0.001 То как меня учили математике, то остаток от деления должен быть равен 0. Почему терминал выдает 0.001? Возможно моя школа устарела?)

void OnStart()
{
   printf("1.01 = %.20f", 1.01);                //1.01 = 1.01000000000000000888
   printf("0.001 = %.20f", 0.001);              //0.001 = 0.00100000000000000002
   printf("fmod = %.20f", fmod(1.01, 0.001) );  //fmod = 0.00099999999999998788
}
 

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Ошибки, баги, вопросы

Nikolai Semko, 2020.01.05 21:41

Постоянно возникает этот вопрос.
Постоянно все говорят о стандарте IEEE 754, но часто люди, когда заходят в википедию – то ли по причине сложности, то ли по причине лени уходят, так и не поняв смысл этого стандарта.

Я потрачу немного времени, чтобы попробовать объяснить этот стандарт максимально коротко и простыми словами, чтобы в дальнейшем ссылаться на это сообщение.


Итак, тип double состоит из 8 байт = 64 бита. (float 4 байта = 32 бита)

И  представление числа double и float состоит из 3 компонентов: знак (sign), экспонента и мантисса  


DOUBLE:


FLOAT:

Естественно, что в данном формате не существует десятичного представления чисел, а только двоичное.

  • Знак – 1 бит. Если 0 – значит + (плюс), если 1 значит – (минус).
  • Экспонента хранит степень для числа 2. Может быть в диапазоне от -12610 до 12710 для float и от – 1022 10 до 102310 для double
  • Мантисса – дробная часть самого числа в двоичной форме, приведенное к такому виду, чтобы запятая стояла после первой единицы без учета этой первой единицы и запятой


Немного понимания двоичного представления чисел и связи их с десятичными:

2 = 10000= 1610

2 = 1000= 810

2 = 100= 4

2 = 10= 2

2 = 1= 110

2 -1 = 0.12 =(1/2)10 = 0.510         

2 -2 = 0.012 = (1/4)10 = 0.2510

2 -3 = 0.0012 = (1/8)10 =  0.12510

2 -4 = 0.00012 = (1/16)10 =  0.062510

2 -5 = 0.000012 = (1/32)10 =  0.0312510

2 -6 = 0.0000012 = (1/64)10 = 0.01562510

2 -7 = 0.00000012 = (1/128)10 = 0.007812510

2 -8 = 0.000000012 = (1/256)10 =  0.0039062510

2 -9 = 0.0000000012 = (1/512)10 =  0.00195312510

2 - 10 = 0.00000000012 = (1/1024)10 =  0.000976562510

2 - 11 = 0.000000000012 = (1/2048)10 =  0.0004882812510

2 - 12 = 0.0000000000012 = (1/4096)10 =  0.00024414062510

2 - 13 = 0.00000000000012 = (1/8192)10 =  0.000122070312510

 

Рассмотрим примеры для типа double:

Пример №1

У нас есть десятичное число: 891677.4025191

Данное число можно представить в двоичном виде:

11011001101100011101.011001110000101101111101111000101000001111101110001110
(кто хочет может проверить)))

Выделяем мантиссу данного числа, просто перенеся запятую на 19 разрядов влево(в данном случае), так чтобы она была после первой единицы.

1.1011001101100011101011001110000101101111101111000101000001111101110001110 * 2 19

Но у нас мантисса всего 52 бита. Значит берем первые 52 значащих бита

Мантисса = 1011001101100011101011001110000101101111101111000101

Экспонента = (19+1023)10 = 100000100102 (т.к экспонента является знаковым числом и экспонента может быть отрицательной (например если у нас число 0.0000042132), то необходимо  сложение с 1023 10 (011111111112), 011111111112 – это ноль, все что больше, это положительные, меньше – отрицательные значения. Т.е. чтобы получить обратно значение степени, то из 11 битного значения экспоненты нужно вычесть 1023.

Итого наше число 891677.4025191 будет выглядеть в типе double следующим образом:

0   10000010010  1011001101100011101011001110000101101111101111000101

Но т.к. это двоичное представление, то переведем его точно в десятичное: 

это будет 891677.402519099996425211429595947265625


Пример №2

У нас есть десятичное число:  -0.00000145258556224114

Данное число можно представить в двоичном виде:

-0.000000000000000000011000010111101100111010110111010011010101001111001110

Выделяем мантиссу данного числа, просто перенеся запятую на 20 разрядов вправо, так чтобы она была после первой единицы.

1.1000010111101100111010110111010011010101001111001110 * 2  -20

Мантисса = 1000010111101100111010110111010011010101001111001110

Экспонента = (-20+1023)10 = 011111010112 

знак минус, значит первый бит равен 1.

Итого наше число -0.00000145258556224114 будет выглядеть в типе double следующим образом:

1   01111101011  1000010111101100111010110111010011010101001111001110

переведем его точно в десятичное: 

это будет -0.00000145258556224113991124017968015191826225418481044471263885498046875



В Вашем случае проблема возникает с числом 0.01, т.к. в типе double оно будет представлено в виде:

0  01111111000   0100011110101110000101000111101011100001010001111011

что при переводе в десятичную систему счисления равно  0.0100000000000000002081668171172168513294309377670288085937510

Тогда как с представлением

310 = 1.5*2 = 1.12*2 1

510 = 2.5*2 = 10.12*2 1

610 = 1.5*4 = 1.12*2 2

710 = 3.5*2 = 11.12*2 1

проблем нет.

Почему число double 0.01 реально больше 0.01?

Вот почему:

0 01111111000 0100011110101110000101000111101011100001010001111011  - 0.01000000000000000020816681711721685132943093776702880859375  погрешность =   0.000 000 000 000 000 000 208166817...

0 01111111000 0100011110101110000101000111101011100001010001111010  - 0.0099999999999999984734433411404097569175064563751220703125    погрешность = - 0.000 000 000 000 000 001 52655666...

Для понимания этой химии процесса можете поиграться с этими калькуляторами:
https://babbage.cs.qc.cuny.edu/IEEE-754.old/Decimal.html

https://baseconvert.com/ieee-754-floating-point


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