函数ceil()、round()、floor()的执行速度 - 页 4

 
Alexey Navoykov:

所以DBL_EPSILON是16位小数:2.2204460492503131e-016

而在你的情况下,你实际上得到了一个,因为差异只有1e-16,这比epsilon少2倍。


在0.999999999999999997下可以工作,但在0.9999999999999998下就不能工作了。

 
Nikolai Semko:

从0.999999999999999997开始工作,但从0.9999999999999998开始就不再工作了。


这里还有一个技巧。

Y=(int)(x+1-2*DBL_EPSILON);
Print(Y);                             // 3
Y=(int)(x+1-DBL_EPSILON-DBL_EPSILON);
Print(Y);                             // 4
 

数字2.2204460492502503131e-016的十进制记数法是指格式为双数的分辨率 (https://msdn.microsoft.com/ru-ru/library/6bs3y5ya(v=vs.100).aspx),这个

最小的正数x,使x+1.0不等于1.0。

- 是最小的正数,在它上面加1.0会改变这个数的值。换句话说,它是一个数字的代表的相对误差。也就是说,对于16来说,这个边界将包含这么多的十进制9,而对于64来说,最后将是1的4倍,8的一半。因此,我们将不得不计算这个精度,以便以尽可能高的精度加快四舍五入的速度。这些计算不太可能比常规四舍五入函数的性能快。由于MQL不允许直接处理数字的地址,我们将不能在数字中取位排序,所以我们将不得不发明基数为2的对数函数的类似物。它不太可能快速发挥作用。

Пределы констант с плавающей запятой
Пределы констант с плавающей запятой
  • msdn.microsoft.com
В следующей таблице представлены ограничения на значения констант с плавающей запятой. Эти ограничения также заданы в стандартном файле заголовка FLOAT.H. Ограничения на константы с плавающей запятой КонстантаЗначениеЗначение Количество цифр q, при котором число с плавающей запятой с q десятичными цифрами можно округлить в представление с...
 
Nikolai Semko:

这里还有一个技巧。

事实证明,任何数学运算都会引入一个额外的误差,这个误差可以是正的,也可以是负的。因此,一般来说,正如弗拉基米尔指出的那样,有必要对结果进行归一化处理。

 

ceil(), floor()不太可能被复制,因为FPU的四舍五入模式不能由μl控制。唯一可能或多或少起作用的是round(),而且根据标准,它并不精确。顺便说一下,这大概是C型圆()的样子。

double round(double x)
{
    fenv_t save_env;
    feholdexcept(&save_env);
    double result = rint(x);
    if (fetestexcept(FE_INEXACT)) {
        fesetround(FE_TOWARDZERO);
        result = rint(copysign(0.5 + fabs(x), x));
    }
    feupdateenv(&save_env);
    return result;
}
 
为了理解你在这里想要四舍五入的内容,你需要确切地知道在将DOUBLE格式转换为INT格式时,如何以及失去了什么。在这种情况下,你只得到整数部分,在四舍五入后仍然存在。因此,任何带有任何数量的小数位 和小数点后的任何数字都将被删除,只留下整数部分。
例子。
2.1758716871 -> (int)2.1758716871 = 2
2.0000000001 -> (int)2.0000000001 = 2
2.9999999999 -> (int)2.9999999999 = 2
当一个数字被重新格式化时, 这被称为准确性的损失
因此
MathFloor(x)  =  (int)(x)
MathCeil(x)   =  (int)(x)+1;
MathRound(x)  =  (int)(x+0.5)

真诚的。
 
Andrey Kisselyov:
为了理解你在这里想要的四舍五入,你需要确切地知道在将DOUBLE格式转换为INT格式时,如何以及失去了什么。在这种情况下,你只得到其中的整数部分,在截断后仍然存在。因此,任何带有任何数量的小数位 和逗号后的任何数字都将被删除,只留下整数部分。
例子:当一个数字被重新格式化时, 这被称为精度的损失
因此

真诚的。

为什么这么复杂?

MathRound(x)  - >  (int)(x)+(int)(2.*(x-(int)(x)));

这比更简单的那个好在哪里呢?

MathRound(x)  ->  (int)(x+0.5);
 
Alexey Navoykov:

事实证明,任何数学运算都会引入一个额外的误差,这个误差可以是正的,也可以是负的。因此,在一般情况下,正如弗拉基米尔所指出的,有必要将结果归一化。


pavlick_

ceil(), floor()不太可能被复制,因为FPU的四舍五入模式不能由μl控制。唯一可能或多或少能起作用的是round(),而且按照标准,它并不精确。顺便说一下,这大约是C型圆()的样子。


当然,你是对的。但我要重复一遍。对于99.9%的任务来说,用替代的更快的变体来取代四舍五入函数是绝对正确的,它使用小数类型转换为(int)或(long)。一个有经验的程序员只需意识到这一事实,并在需要时加以应用。

Для положительных x:
y=floor(x); -> y=(int)x;
y=ceil(x);  -> y=(int)(x+0.9999999999999997);
y=round(x); -> y=(int)(x+0.5);
 
Nikolai Semko:

为什么这么复杂?

这比更简单的那个好在哪里呢?

你可以试试这种方式。

尼古拉-森科
有经验的程序员只需意识到这一事实,并在适当的时候应用它。

不是说他必须,而是他必须知道。

恕我直言。

P.S. 你的公式对整个数值集来说是不正确的。
y=ceil(x);  -> y=(int)(x+0.9999999999999997);
看到我的,我更新了一轮,变成了一个简短的公式,现在的清单是完整的,功能齐全,使用它。
 
Andrey Kisselyov:


P.S.你的公式对整组数值来说是不正确的。

看到我的,我更新了一轮,变成了一个简短的公式,现在的清单是完整的,功能齐全,使用它。

上文

当x=3(任何整数)时,就会出现卡壳现象:))