mql5 双精度失真问题

 
//---lotsTest (EURUSD,H1) 0.9399999999999999

   Print(NormalizeDouble(1.88/2,2));

1.88 除以2 。结果是   0.9399999999999999。 

我的需求是计算现在仓位的一半。双精度失真的这个问题是怎么解决的?

 
最笨的方法就是先乘上100再相除
 
ThrallOtaku:
//---lotsTest (EURUSD,H1) 0.9399999999999999

   Print(NormalizeDouble(1.88/2,2));

1.88 除以2 。结果是   0.9399999999999999。 

我的需求是计算现在仓位的一半。双精度失真的这个问题是怎么解决的?

Print(DoubleToString(1.88/2,2));

 

部分浮点数在计算机中无法精确表示。

1.88/2= 0.94(数学上),计算机中0.94的真实表示在64位机器中是0.939999999999999947

所以NormalizeDouble(0.939999999999999947,2) = 0.94(数学上),计算机又把它表示为0.939999999999999947

所以要平仓一半可能存在问题?写个EA验证下,看看平仓有没有问题?

 
Ziheng Zhuang:

部分浮点数在计算机中无法精确表示。

1.88/2= 0.94(数学上),计算机中0.94的真实表示在64位机器中是0.939999999999999947

所以NormalizeDouble(0.939999999999999947,2) = 0.94(数学上),计算机又把它表示为0.939999999999999947

所以要平仓一半可能存在问题?写个EA验证下,看看平仓有没有问题?


ea 报错平不了的。

 
Daying Cao:

Print(DoubleToString(1.88/2,2));

我要的是浮点数。 toString 的数据不能传给 request 进行ea交易

 

我简单测试下,可以通过平半仓。

//+------------------------------------------------------------------+
//|                                                     test_094.mq5 |
//|                                           Copyright 2020,fxMeter |
//|                            https://www.mql5.com/en/users/fxmeter |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020,fxMeter"
#property link      "https://www.mql5.com/en/users/fxmeter"
#property version   "1.00"

#include <Trade\Trade.mqh>
CTrade         TradeObj;
long MagicNumber = 1235;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
//---

   TradeObj.SetExpertMagicNumber(MagicNumber);
   TradeObj.SetMarginMode();
   TradeObj.SetTypeFillingBySymbol(Symbol());
   TradeObj.SetDeviationInPoints(30);
//---
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
//---
   if(!MQLInfoInteger(MQL_TESTER))return;//only test

//...test
   double lots = 1.88;
   static datetime last = 0;

   if(PositionsTotal()==0)
   {
      TradeObj.Buy(lots);
      last=TimeCurrent();
      return;
   }

   static int flag=0;
   if(PositionsTotal()>0 && flag==0 && TimeCurrent()>last+3600*10)
   {
      double lots2 = lots/2;
      lots2 = NormalizeDouble(lots2,2); //简单处理
      ResetLastError();
      if(!TradeObj.PositionClosePartial(Symbol(),lots2))
      {
         Print("lots2 = ",lots2);
         Print("error = ",GetLastError());
      }
      else
      {
         Print("lots2 = ",lots2);
         flag = 1;
      }
   }

}
//+------------------------------------------------------------------+
//2021.05.22 19:02:41.514       2021.04.01 10:00:20   lots2 = 0.9399999999999999
 

测试结果:


 
ThrallOtaku:
//---lotsTest (EURUSD,H1) 0.9399999999999999

   Print(NormalizeDouble(1.88/2,2));

1.88 除以2 。结果是   0.9399999999999999。 

我的需求是计算现在仓位的一半。双精度失真的这个问题是怎么解决的?

一般仓位处理都需要格式化一下的

formatlots(string symbol,double dlots)

  {

   double min=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN);

   double step=SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP);

   if(dlots>=min)

     {

      double l=MathFloor(dlots/min)*min+MathFloor((dlots-MathFloor(dlots/min)*min)/step)*step;

      return(l);

     }

   else

     {

      return(dlots);

     }

  }


 
將計算結果採小數第二位後 先轉成文字 再轉回浮點數 應該就可以用的
 
ThrallOtaku:
//---lotsTest (EURUSD,H1) 0.9399999999999999

   Print(NormalizeDouble(1.88/2,2));

1.88 除以2 。结果是   0.9399999999999999。 

我的需求是计算现在仓位的一半。双精度失真的这个问题是怎么解决的?

个人认为完整解决方案

double mstep=MarketInfo(m_sym,MODE_LOTSTEP);      
int digitslots=(int)log10(1/mstep);
c_lots=NormalizeDouble(1.88/2.0,digitslots);
你Print()试试。