如何在D中执行高精度计算?

NaN*_*NaN 4 floating-point d arbitrary-precision

对于一些普遍的工作,我必须近似一些数字 - 比如欧拉系列.因此我必须添加非常小的数字,但我的精度有问题.如果数量非常小,则不会影响结果.

real s;  //sum of all previous terms
ulong k; //factorial

s += 1.0/ k;
Run Code Online (Sandbox Code Playgroud)

在每一步之后,k变得更小,但在第10轮之后,结果不再变化并且停留在2.71828

jgo*_*ula 9

固定精度浮点类型,那些原生你的CPU的浮点单元支持(float,double,real)不是最佳的,需要精确很多数字,比如你给的例子任何计算.

问题是这些浮点类型具有有限位数的精度(实际上是二进制数字),这限制了可以由这种数据类型表示的数字长度.该float类型的限制大约为7位小数(例如3.141593); 该double类型被限制为14(例如3.1415926535898); 并且real类型具有类似的限制(略大于double).

因此,将极小的数字添加到浮点值将导致这些数字丢失.观察当我们将以下两个浮点值一起添加时会发生什么:

float a = 1.234567f, b = 0.0000000001234567
float c = a + b;

writefln("a = %f b = %f c = %f", a, b, c);
Run Code Online (Sandbox Code Playgroud)

两个ab是有效的浮点值,并保留约7的精度位数每人在隔离.但是当添加时,只保留最前面的7位数字,因为它被推回到浮点数:

1.2345670001234567 => 1.234567|0001234567 => 1.234567
                              ^^^^^^^^^^^
                         sent to the bit bucket
Run Code Online (Sandbox Code Playgroud)

所以c最后等于a,因为从另外的精度更精细的数字a,并b得到疲惫不堪了.

这是对这个概念的另一种解释,可能比我的好得多.


这个问题的答案是任意精度算术.不幸的是,对任意精度算术的支持不在CPU硬件中; 因此,它(通常)不是您的编程语言.但是,有许多库支持任意精度浮点类型以及要对它们执行的数学运算.请参阅此问题以获取一些建议.你今天可能找不到任何特定于D的库,但是有很多C库(GMP,MPFR等)应该很容易单独使用,如果你能找到它们就更是如此其中一个的D绑定.