NormalizeDoubleによるMT4での数値の丸め方 - ページ 16

 
fxsaber:
時代遅れ

標準ライブラリには、粒度を考慮した価格正規化関数がある

//+------------------------------------------------------------------+
//| Normalize price                                                  |
//+------------------------------------------------------------------+
double CSymbolInfo::NormalizePrice(const double price) const
  {
   if(m_tick_size!=0)
      return(NormalizeDouble(MathRound(price/m_tick_size)*m_tick_size,m_digits));
//---
   return(NormalizeDouble(price,m_digits));
  }
 
Slawa:

標準ライブラリには、粒度を考慮した価格正規化関数がある

この極端に遅い実装は承知しています。NormalizeDouble(とHelp)を現在の実情に合わせて微調整することでした。誰もが自分のグラニュを書くことができる。
 
transcendreamer:
NormalizeDouble(new_lot-sum_lots,Lots_Digits); では正確に0を出力せず、末尾を保存しているのではないかと思い始めていました。

変数new_lotとsum_lotsが等しい場合、その差はちょうど0となる。しかし、どのように計算したかは不明です。計算すると確かに不等間隔になる可能性があり、そのため差がゼロにならないのです。同じことをこうやってやるんだ。

NormalizeDouble(new_lot, Lots_Digits) - NormalizeDouble(sum_lots, Lots_Digits)です。

変数が指定された桁数以内で等しい場合、その差は厳密に0になります。

 
Sergei Vladimirov:

変数new_lotとsum_lotsが等しい場合、その差はちょうど0となる。しかし、どのように計算したかは不明です。計算すると確かに不等間隔になる可能性があり、そのため差がゼロにならないのです。同じことをこうやってやるんだ。

NormalizeDouble(new_lot, Lots_Digits) - NormalizeDouble(sum_lots, Lots_Digits)です。

指定された桁数の範囲内で変数が等しい場合、その差は厳密に0となる。

おはこんばんちは
 
transcendreamer:

また四捨五入の話か......。

状況に応じてアドバイスをお願いします(トマトを投げないでください、私は人情派です)。

があり、そのような変数があります。

      double delta=NormalizeDouble(new_lot-sum_lots,Lots_Digits);

      if(delta>0) delta-=OrderLots();

      if(delta<0) delta+=OrderLots();

デルタはもともと正規化されています。

OrderLotsは、おそらく正規化されたダブを返すはずです。

が、なぜかまれに2.775557561562891e-17のような数字が表示されることがある。

だから、ほぼゼロだけどゼロじゃない......。

最初の質問:これは正常なのでしょうか?

...


もう一度よく読んでみました。普通じゃないんです。NormalizeDouble関数の 動作。

  1. 整数部が選択される - I
  2. 分数部を選択 - F
  3. F = F * 10^digits
  4. F=F(符号により+または-) 0.5
  5. F = (Fの整数部) / 10^digits
  6. 結果=I+F
の場合、NormalizeDouble(new_lot - sum_lots, Lots_Digits) の 結果もnew_lot と sum_lots が指定桁数以内で等しければ厳密に0に なるはずです。まれに最後の桁に1の差が出ることがありますが(理由は項目4と5にあります)、2.775557561562891e-17という結果はおかしい、あってはならないことなのです。
 

私は、浮動小数点数の内部を判明させる小さなチュートリアルコードを書きました(自分でつつくことに興味があったのです)。もし、興味がある人がいれば、それを実行することができます(C++コード、あなたはいくつかのオンラインコンパイラーを使用することができます)。こちらhttps://goo.gl/tP691X、 例)

#include <iostream>
using namespace std;

int main()
{
    cout.precision(17);
    float f = 0.5;
    //float add = 0.00000002980232239; //-25   1/(2^25)
    float add = 0.00000005960464478; //-24     1/(2^24)
    //float add = 0.0000001192092896; //-23   1/(2^23)
    //float add = 0.0000002384185791; // -22  1/(2^22)
    f+= add;

    cout << "value = " << f << endl;
    cout << "----------\n";

    char *c = (char*)&f;  // char может ссылаться на любой тип
    cout << "mantissa:\n";
    cout << "implicit_1 ";
    cout << (c[2] >> 6 & 0 b1) << ' '; cout << (c[2] >> 5 & 0 b1) << ' ';
    cout << (c[2] >> 4 & 0 b1) << ' '; cout << (c[2] >> 3 & 0 b1) << ' ';
    cout << (c[2] >> 2 & 0 b1) << ' '; cout << (c[2] >> 1 & 0 b1) << ' ';
    cout << (c[2] >> 0 & 0 b1) << ' '; cout << (c[1] >> 7 & 0 b1) << ' ';
    cout << (c[1] >> 6 & 0 b1) << ' '; cout << (c[1] >> 5 & 0 b1) << ' ';
    cout << (c[1] >> 4 & 0 b1) << ' '; cout << (c[1] >> 3 & 0 b1) << ' ';
    cout << (c[1] >> 2 & 0 b1) << ' '; cout << (c[1] >> 1 & 0 b1) << ' ';
    cout << (c[1] >> 0 & 0 b1) << ' '; cout << (c[0] >> 7 & 0 b1) << ' ';
    cout << (c[0] >> 6 & 0 b1) << ' '; cout << (c[0] >> 5 & 0 b1) << ' ';
    cout << (c[0] >> 4 & 0 b1) << ' '; cout << (c[0] >> 3 & 0 b1) << ' ';
    cout << (c[0] >> 2 & 0 b1) << ' '; cout << (c[0] >> 1 & 0 b1) << ' ';
    cout << (c[0] >> 0 & 0 b1) << '\n';
    cout << "exponenta E - 127:\n";
    cout << "1= " << (c[2] >> 7 & 0 b1) << '\n';
    cout << "2= " << (c[3] >> 0 & 0 b1) << '\n';
    cout << "4= " << (c[3] >> 1 & 0 b1) << '\n';
    cout << "8= " << (c[3] >> 2 & 0 b1) << '\n';
    cout << "16= " << (c[3] >> 3 & 0 b1) << '\n';
    cout << "32= " << (c[3] >> 4 & 0 b1) << '\n';
    cout << "64= " << (c[3] >> 5 & 0 b1) << '\n';
    cout << "128= " << (c[3] >> 6 & 0 b1) << '\n';
    cout << "sign\n";
    cout << (c[3] >> 7 & 0 b00000001) << '\n';
}

fでの出力 == 0.5 + 1/(2^24)。1/(2^24)は、ある度数での仮数の最下位桁です。

value = 0.50000005960464478
----------
mantissa:
implicit_1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
exponenta E - 127:
1= 0
2= 1
4= 1
8= 1
16= 1
32= 1
64= 1
128= 0
sign
0

度数=126-127=-1

仮数 = 1.00000000000000000000001

仮数を次数にシフトする -1 = 0.100000000000000001 = 1^(-1) + 1^(-24) = 1/(2^1) + 1/(2^24) = 0.5 + 0.00000005960464478 = 0.50000005960464478


理論としてhttps://habrahabr.ru/post/112953/。

SZZ:このオンラインコンパイラは、http://rextester.com/l/cpp_online_compiler_gcc よりも素敵です。

 
pavlick_:

私は、浮動小数点数の内部を判明させる小さなチュートリアルコードを書きました(自分でつつくことに興味があったのです)。もし、興味がある人がいれば、それを実行することができます(C++コード、あなたはいくつかのオンラインコンパイラーを使用することができます)。こちらhttps://www.tutorialspoint.com/compile_cpp11_online.php、 例)

このライブラリを 接続することで、c[Pos]を _R(f)[(char)Pos] (または _R(f).Bytes[Pos]) に置き換え、MQL5で実行することも可能です。

エスゼット

#include "fmtprntl.mqh"    // https://www.mql5.com/en/blogs/post/680570
#include <TypeToBytes.mqh> // https://www.mql5.com/ru/code/16280

#define  c _R(f).Bytes
#define  endl "\n"

void OnStart()
{
  OutputStream cout(16, ' ');
  
  float f = 0.5;
  //float add = 0.00000002980232239; //-25   1/(2^25)
  float add = 0.00000005960464478; //-24     1/(2^24)
  //float add = 0.0000001192092896; //-23   1/(2^23)
  //float add = 0.0000002384185791; // -22  1/(2^22)
  f+= add;

  cout << "value = " << f << endl;
  cout << "----------\n";

  cout << "mantissa:\n";
  cout << "implicit_1 ";
  cout << (c[2] >> 6 & 1) << ' '; cout << (c[2] >> 5 & 1) << ' ';
  cout << (c[2] >> 4 & 1) << ' '; cout << (c[2] >> 3 & 1) << ' ';
  cout << (c[2] >> 2 & 1) << ' '; cout << (c[2] >> 1 & 1) << ' ';
  cout << (c[2] >> 0 & 1) << ' '; cout << (c[1] >> 7 & 1) << ' ';
  cout << (c[1] >> 6 & 1) << ' '; cout << (c[1] >> 5 & 1) << ' ';
  cout << (c[1] >> 4 & 1) << ' '; cout << (c[1] >> 3 & 1) << ' ';
  cout << (c[1] >> 2 & 1) << ' '; cout << (c[1] >> 1 & 1) << ' ';
  cout << (c[1] >> 0 & 1) << ' '; cout << (c[0] >> 7 & 1) << ' ';
  cout << (c[0] >> 6 & 1) << ' '; cout << (c[0] >> 5 & 1) << ' ';
  cout << (c[0] >> 4 & 1) << ' '; cout << (c[0] >> 3 & 1) << ' ';
  cout << (c[0] >> 2 & 1) << ' '; cout << (c[0] >> 1 & 1) << ' ';
  cout << (c[0] >> 0 & 1) << '\n';
  cout << "exponenta E - 127:\n";
  cout << "1= " << (c[2] >> 7 & 1) << '\n';
  cout << "2= " << (c[3] >> 0 & 1) << '\n';
  cout << "4= " << (c[3] >> 1 & 1) << '\n';
  cout << "8= " << (c[3] >> 2 & 1) << '\n';
  cout << "16= " << (c[3] >> 3 & 1) << '\n';
  cout << "32= " << (c[3] >> 4 & 1) << '\n';
  cout << "64= " << (c[3] >> 5 & 1) << '\n';
  cout << "128= " << (c[3] >> 6 & 1) << '\n';
  cout << "sign\n";
  cout << (c[3] >> 7 & 1) << '\n';
}

結果

2016.09.27 23:56:01.178 Test (Si-12.16,H1)       0
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      sign
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      128=  0
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      64=  1
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      32=  1
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      16=  1
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      8=  1
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      4=  1
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      2=  1
2016.09.27 23:56:01.178 Test (Si-12.16,H1)       1=  0
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      exponenta E - 127:
2016.09.27 23:56:01.178 Test (Si-12.16,H1)       implicit_1  0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 1
2016.09.27 23:56:01.178 Test (Si-12.16,H1)       mantissa:
2016.09.27 23:56:01.178 Test (Si-12.16,H1)       ----------
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      value =  0.5000000596046448 
 
implicit_1  0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 1

仮数はどうなったのでしょうか?

32は問題のアスキーコードです。エラーのある ライブラリは、charのバージョンがないようです。仮数値間の問題を取り除く必要があると思います。あるいは、' ' の代わりに " " を書くとか?

 
pavlick_:

仮数はどうなったのでしょうか?

32は問題のアスキーコードです。バグのあるライブラリのようです。仮数値間の問題を取り除く必要があると思います。あるいは、' ' の代わりに " " を書くとか?

fmtprntl.mqhは私のものではないので、なんとも言えません。

面倒なので、fのプリント バイトの値に対して

2016.09.28 00:34:09.813 Test (Si-12.16,H1)      c[0] = 1
2016.09.28 00:34:09.813 Test (Si-12.16,H1)      c[1] = 0
2016.09.28 00:34:09.813 Test (Si-12.16,H1)      c[2] = 0
2016.09.28 00:34:09.813 Test (Si-12.16,H1)      c[3] = 63
 
Slawa:

関連する副作用

便利であることがわかった。しかし、本来はこのような使い方は想定していない。

実数を必要な精度で印刷するための特殊な機能があります。

計算過程で実数を丸める必要がある理由を教えてください。なぜなら、この場合、計算精度が落ちてしまうからです

私たちは、価格、停止、ロットの正しい比較について話しています

ここには、ある種の正確さが必要です。

理由: