価格 != 価格 ?

 

私は、私が見ている奇妙な何かを理解しようとしているので、私は将来的にそれを丸めるより良いコードを作ることができます... ...

私は自分のインジケータで何か奇妙なことが起こっていることに気づきました、それはそれがそうであるべきではなかったので、私はコードをチェックし、それが正しいように見えました。 そこで、私は少し調査して、小さなテスト指標を 作成することにしました。

基本的にこれは真実であるように思われます。

double TestValue = iClose(NULL, 0, 0);
   
if(TestValue != NormalizeDouble(TestValue, Digits) )

このようなことが起こるのはなぜでしょうか?

 
過去の質問と回答
 
RaptorUK:

.... どうすればこのようなことが起こるのか、何か心当たりはありませんか?

NormalizeDouble() の内部動作に起因しています。例えば...

   double TestValue = 1.57373;
   if (TestValue != NormalizeDouble(TestValue, 5)) MessageBox("WTF?");

ちなみに、以下のようにしても同じ結果になります。

   double TestValue = StrToDouble("1.57373");
   if (TestValue != NormalizeDouble(TestValue, 5)) MessageBox("WTF?");

最初の代入の後、TestValue = 1.5737300000000001.これに対して NormalizeDouble(..., 5) は 1.573729999999 を生成します。

 
WHRoeder:
過去の質問と回答
失礼ながら、その投稿はこのスレッドにおける私の問題に答えているとは思えません。
私はこれを行うにはNormalizeDouble以外の方法があることを知っている ... 私が理解していないのは、iCloseがすでに正規化されていない値を返している理由です ... 。
 
jjc:

NormalizeDouble()の内部動作に起因しています。例えば...

ちなみに以下のようにしても同じ結果です。

最初の代入の後、TestValue = 1.5737300000000001 となります。これに対して NormalizeDouble(..., 5) は 1.573729999999 を生成します。


では、どうすれば TestValue が 1.57373 になり、 > や < にならないのでしょうか?
 
RaptorUK:

では、TestValueが>でも<でもなく、1.57373になるようにするには、どうすればいいのでしょうか?
念のため言っておきますが、1.57373は浮動小数点値として 正確に表現することはできません。0.1のような値も同様です。唯一の奇妙な点は、NormalizeDouble()がMQ4言語の他の部分と異なる近似値を使用してしまうことです。
 
jjc:
念のため言っておくと、1.57373は浮動小数点値として正確に表現することはできない。 0.1 のような値も同様です。唯一の奇妙な点は、NormalizeDouble()がMQ4言語の他の部分と異なる近似値を使用してしまうことです。

ああ......いえ、明確ではありませんでした......知りませんでした。 ありがとうございます、調査してみます。
 
RaptorUK:
ああ......いや......明確ではなかった......知りませんでした。 ありがとう、調べてみるよ。

浮動小数点値と演算は、コンピュータのプロセッサに組み込まれているため高速ですが、浮動小数点型変数で正確に表現できない値もあるというトレードオフがあります。(速度に関する例としては、https://www.mql5.com/en/forum/116228/page2#156859 を参照してください)。

事実上、倍数を含むすべてのものは、一種の丸め誤差を引き起こす可能性があります。このため、いろいろと楽しい癖があります。例えば、0.1 * 10 = 1.0 ですが、0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1!= 1.0 となります。

この結果、NormalizeDouble(x, y) は Round(x, y) と正確には同義ではありません。NormalizeDouble() は、丸められた値にできるだけ近い浮動小数点数の近似値を返します。NormalizeDouble(a, n) == NormalizeDouble(b, n) とした場合、基本的には「浮動小数点演算で小数点以下n桁以上の丸め誤差が発生する可能性を考慮して、aとbは等しいか」と言うことになるのです。

多くの人が言っているように、NormalizeDouble(a, 5) == NormalizeDouble(b, 5) はしたがって実質的に MathAbs(a - b) < 0.00001 と同じで、後者の方が若干実行速度が速いです。後者は、NormalizeDouble()関数に相当する便利な関数を提供しない言語/プラットフォームで広く使用されているため、一般的なものでもあります。しかし、この性能差は非常に小さいので、もしその方がコードが読みやすいと感じるのであれば、私はNormalizeDouble()にこだわります。

このようなことは、doubleデータ型を持つ言語では全く普通のことです。ただし、1.57373 != NormalizeDouble(1.57373, 5) というのは、MQ4独自の、典型的な癖のある表現です。定数 1.57373 を宣言するのと NormalizeDouble() を使用するのとで、異なる最良ケースの浮動小数点近似値が選択されるのは曲者です。

 

ありがとうございます :-)

私はこの問題に気づいていましたが、その理由をよく理解しておらず、それゆえ起こりうる影響についても十分に理解していませんでした。

 
ただし、ゼロの場合は倍数を比較しない
if (a > b)
if (a - b > Point / 2.)
if (a >= b)
if (a - b > -Point)
if (a != b)
if (MathAbs(a - b) > Point / 2.)
 
WHRoeder:
ただし,ゼロの場合は倍精度比較はしない


私はまさにそれを行っている100行強のコードを持っています ... そして、それを確実に動作させるために、目に見えるほとんどすべてのものにNormalizeDoubleを使用して います。 私はあなたの提案の背後にある考えを理解し、ありがとうございます、しかし、私はそれが私のコードの読みやすさと、したがって、将来の修正の容易さに悪影響を及ぼす可能性があると思います。

私は、遠くない将来、このコードのブロックを修正して、実行中のチャートのタイムフレーム以外のタイムフレームで動作するようにするつもりです。 その時は、NormalizeDoublesを削除して、何か他のものに置き換えるつもりです ... まだ100%確実ではありませんが、比較の前に整数への変換をするかもしれません ...

いつもながら、ありがとうございます :-)