0.3 ÷ 0.1 = 2 余り 0.1 ??
ポロリ 2010/03/28 16:19
はじめまして。いつも参考にさせていただいております。EA作成中に困ったことが発生してしまったので
質問させてください。割り算の余りを出力するMathModで、
MathMod(1.1,0.1)とMathMod(0.3,0.1)なのですが、
前者は戻り値0、後者は戻り値が0.1となります。私は両者とも戻り値0にしたいのですが、
どのようにすればよいのでしょうか?
昨日コメントを頂いて既に回答した話ですが、大事なことなので記事にしておきます。
MathMod を使用して、0.3 ÷ 0.1 の余りを求めると…
Print( MathMod(0.3,0.1) ); // 出力値は 0.1 (°▽°;)
余りが 0.1 になってしまいます..。
何故こんな現象が起きるのかというと、コンピュータの二進数の世界では 0.1 を正確に表現できないのが原因です。
[10進数] 0.1 = [2進数] 0.000110011001100110011…………
1/3 を小数で表現すると 0.3333…と無限に続くのと同様に、2進数の 0.1 は無限に続きます。無限に表記することはできないので、循環小数は途中で打ち切ることになり、そこで誤差(丸め誤差)が生じます。
(これは 0.1 以外にもいろんな数値で起こりえる話です。)
丸め誤差を MQL4 の枠組みで体感するのは難しくて、
#includePrint( DoubleToStrMorePrecision(0.1*3,16) ); // 出力値は 0.3000000000000001
上記のように 0.1 を3倍(or 6倍,7倍)して、DoubleToStrMorePrecision 関数で、16桁の精度で表示させると、16桁目に誤差らしき数値が現われます。
ちなみに、MQL5 では MathMod(0.3,0.1) は 0.09999999999999998 と出力されるので、丸め誤差の問題に気付きやすいはずです。
…で、今回の問題を回避する方法ですが、MathModに渡る引数が整数となるようにするのが簡便です。
Print( MathMod(0.3*10,0.1*10)/10 );
ただ、これだけでは回避しきれない場合もあるので、
Print( MathMod(NormalizeDouble(0.3*10,0),NormalizeDouble(0.1*10,0))/10);
とするのが良いかも知れません。。