程序库: 数学工具 - 页 6

 
如果您需要自定义函数,以获得与铸入 (string)dbl 完全相同的最短字符串,请使用库中的 Repr() 函数:

字符串 shortest_str = Repr(dbl) 。

在 MQL 开发人员修复了字符串和 Print() 的错误以符合 ieee-754 标准之前,这个函数曾经是必需的。
 

但愿你是对的,事情就这么简单。如果这么简单,我就不会在这里了,也绝对不会浪费这么多工作时间在这上面。


的确,我需要

1. 控制小数点后的位数

2. 动态调整位数,使其尽可能短


我的双倍数来自

Tickvalue ->SYMBOL_TRADE_TICK_VALUE

TickSize -> SYMBOL_TRADE_TICK_SIZE

LotValue = ((TickValue / TickSize) * lot);


没什么奇怪的,标准值,都很好,但 LotValue 似乎很难格式化并显示在屏幕上。


最大的问题是,我的双倍值显示为 1.000000000,但实际上是 1.000000001。

(我知道双倍值是如何工作的,也知道这是正常现象)


Print()、DoubleToString()、NormalizeDoubles() 和 StringFormat() 基本上都是对数字进行四舍五入,结果数字错得离谱;什么都不管用,MQL4 内置函数根本无法达到所需的精度,因为它们会对数字进行四舍五入,1.000000000 最终等于 1.1。

(我想不出在任何情况下,不断显示 "价格 "的应用程序看到一个从 1.04966 到 1.0497 的 "伪造 "数字会有多方便,但这是后话。)


这就是为什么一开始我使用一个简单的公式来获得所需的精度。

int p = 5; // 所需的精度

double n = 1.000000000;

double p10 = (p * 10);

double(long(n * p10) / p10);

但是,当我使用的不是外汇,而是加密货币时,情况就变得复杂了,我需要 9-10 的更高精度,而在此精度之上,我无法去除尾数零,因此我使用了您的函数。

所有这些麻烦都是因为我需要向用户输出尽可能多的信息,而屏幕空间有限,所以我需要在固定的空间内挤出数字。


您的函数 Trunc() 可以处理 99.9% 的数字,但有些数字不配合,需要特殊处理。

我希望你能给出一个简化的公式。


现在,Round(double, int) 函数又给我添了麻烦,它让 MT4 在执行某些双数时停止。不知道为什么,双倍值并不大,只有 100000.0000000000

这是一个代表欧元兑美元 1 手价值的普通数字,如果我手写这个值,一切都没问题,但如果它来自数学 LotValue = ((TickValue / TickSize) * lot); MT4 就会阻塞。


这么简单的任务,我已经花了 40 多个小时。这简直要了我的命

 
Cristian Dan Fechete #:

我确实需要这样做:

1. 控制小数点后的位数

2. 动态调整位数,使其尽可能短


我告诉你
double n = 1.000000000;
是相同的:
double n = 1.0;

您的要求:
字符串中的小数 <= 指定的数字

如果您的唯一要求是将数字格式化为尽可能短的字符串,不带尾数 0(同时控制小数位数的最大值):

string s1 = (string) Round(number, digits);

string s2 = (string) NormalizeDouble(number, digits);

string s3 = StringFormat("%.5f", number);
请选择其中任何一种形式。

四舍五入和 NormalizeDouble 将控制小数点后的最大位数。然后,转换为字符串 (string)dbl 将得到尽可能短的字符串,但不包括尾部的零。StringFormat() 的作用与此相同,但如果在代码中调用数百万次,速度似乎会慢一些。

就你的情况而言,不建议使用 DoubleToString(),因为它会在较短的字符串 < 位数处填充尾部的 0,以保持固定的小数位数。这不是你所要求的。您要求的是动态的小数位数(最短)。

编辑:
你的精确度计算错误
int p = 5; // 期望精度
double p10 = (p * 10);

应该计算为
int p = 5; // 期望精度
double p10 = MathPow(10, p);

 

看来我发了 4 条信息也没能让您理解我的问题,我对自己的失败感到非常失望。

而且这个网站的样式表完全有问题,所以在这里写留言非常耗时。

double n = 1.000000000; 
should be the same as:
double n = 1.0;
but it is NOT

我无法解释原因,但我们必须假设 1.000000000; 在某个地方有一个 0 以外的小数位,尽管我无法用图形输出它。

但结果是

string s1 = (string) Round(number, digits);  -> blocks MT4

string s2 = (string) NormalizeDouble(number, digits); -> returns a 'faked' string where a rounding is done on last digit

string s3 = StringFormat("%.5f", number); -> same as NormalizeDouble()

对于 19.65400 这样的数字

string s = (string) Trunc(number, digits);

可以完美运行。如果我手动输入 1.0000000,它也能正常工作。

为了让你理解我的意思,我在 400 多个不同参数上使用了该函数,每个参数在每个刻度上都有不同的值,Trunc() 可以完美地工作。

但对于

double lotValue = ((_TickValue / _TickSize) * lot);

这就是为什么我也使用了 Round(number, digits) 函数;它曾经很有效,我决定直接问你是否有公式可以将我的 Normalize_Double_ToString() 函数合并为更简单、更优化的代码。

而你给我的回答却大相径庭(我认为这完全是我没有解释清楚的错)

但从昨天开始,Round() 阻止了 MT4,如果不使用 Round,我就无法正确计算小数部分的有效数字。

问题似乎出在对 long 的类型转换上。如果我将其从 Round(double, int); 中移除,MT4 的执行就没有问题,但我不知道一个有 6 位整数的 double 乘以 10000 如何达到 long 的极限。


我想此时我的问题是:出口在哪里?

出口在哪里?


不管怎样,我得先把这个问题放一放,过几周再继续研究。

 

试试这个

string Normalize_Double_ToString(double n, int d)
{
   n = Round(n, d);
   d = MathMin(d, GetDigits(n);

   return DoubleToString(n, d);
}

不过, 这并不比上一篇文章中的 3 个简短方法好多少。

注意

我使用的是我的库中的 Round(),而不是你之前发的那个错误的 Round():

n = NormalizeDouble(n,d);

但是,我怀疑你所说的 Round() 有错误。
 
Cristian Dan Fechete #:

看来我发了四条信息也没能让你理解我的问题,我对自己的失败感到非常失望。

而且这个网站的样式表完全有问题,所以在这里写留言非常耗时

我无法解释原因,但我们必须假设 1.000000000; 在某个地方有一个 0 以外的小数位,尽管我无法用图形输出它。

我相信我已经了解您在 MT4 上遇到问题的原因。

您无法获得预期结果的主要原因是 MQL4 string(dbl) 的一个错误,该错误在 MT4 上仍未修复。

MQL4 string() 函数中的错误。double -> string 的错误转换。

这也会影响 Print()、Alert()、Comment()、FileWrite() 如何显示 double(通过隐式转换为字符串)。

该错误已在 MT5 上修复,但在 MT4 上未修复。请参见此处:https://www.mql5.com/en/forum/367839/page3#comment_27477157 和 此处的修复方法:https://www.mql5.com/en/forum/367839/page5#comment_27613205

我的建议

如果您想深入研究或调试 MT4 中以字符串形式显示的加倍值,请始终通过 math_utils.mqh 中的Repr() 函数 强制将加倍值明确转换为字符串。

#include "math_utils.mqh"

//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnStart()
  {
   double a = 1.0000000000000002;
   Print(a);         //1.0(隐式 double -> string 中的错误)
   Print(Repr(a));   // 1.0000000000000002

   double b = 100.00000000000003;
   Print(b);         //100.0(隐式 double -> string 中的错误)
   Print(Repr(b));   // 100.00000000000003
  }
MT5/mql5 reported and confirmed bugs. - Custom ZERO Level Showing ZERO level, bug in MML. String(MQ)
MT5/mql5 reported and confirmed bugs. - Custom ZERO Level Showing ZERO level, bug in MML. String(MQ)
  • 2022.02.01
  • Alain Verleyen
  • www.mql5.com
On indicators, mt5 can set automatically a level "0" depending of the buffer values. Custom indicator showing zero level, though not defined anywhere in the code. Wrong conversion of double -> string. Then test the same example in your browser js pad or any online javascript pad and check the difference