如何在D中进行高精度计算?
对于一些大学工作,我必须近似一些数字 - 例如带有级数的欧拉数字。因此我必须添加非常小的数字,但我在精度方面存在问题。如果数量很小,则不会影响结果。
real s; //sum of all previous terms
ulong k; //factorial
s += 1.0/ k;
每一步之后,k 都会变得更小,但是在第 10 轮之后,结果不再改变并停留在 2.71828
For some universitary work i have to approximate some numbers - like the Euler one with series. Therefore i have to add very small numbers, but i have problems with the precision. If the number ist very small it doesn't influence the result.
real s; //sum of all previous terms
ulong k; //factorial
s += 1.0/ k;
after each step, k gets even smaller, but after the 10th round the result isn't changeing anymore and stuck at 2.71828
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
固定精度浮点类型,即 CPU 浮点单元本身支持的类型(
float
、double
、real
)对于任何情况都不是最佳选择。需要多位精度的计算,例如您给出的示例。问题在于,这些浮点类型的精度位数(实际上是二进制数字)有限,这限制了此类数据类型可以表示的数字长度。
float
类型的限制为大约 7 位十进制数字(例如 3.141593);double
类型限制为 14(例如 3.1415926535898);而real
类型也有类似的限制(比double
略多)。因此,将极小的数字添加到浮点值将导致这些数字丢失。观察将以下两个浮点值相加时会发生什么:
a
和b
都是有效的浮点值,并且各自保留大约 7 位精度。但添加后,仅保留最前面的 7 位数字,因为它被推回浮点数:因此
c
最终等于a
,因为加法的精度更高a
和b
被击落。这是这个概念的另一种解释,可能比我的好得多。
这个问题的答案是任意精度算术。不幸的是,CPU 硬件不支持任意精度算术;因此,它(通常)不是您的编程语言。但是,有许多库支持任意精度浮点类型以及您想要对其执行的数学运算。请参阅此问题获取一些建议。今天您可能找不到任何用于此目的的 D 特定库,但有大量 C 库(GMP、MPFR 等)应该很容易单独使用,如果您能找到,则更是如此其中之一的 D 绑定。
Fixed-precision floating point types, the ones natively supported by your CPU's floating point unit (
float
,double
,real
) are not optimal for any calculation that needs many digits of precision, such as the example you've given.The problem is that these floating-point types have a finite number of digits of precision (binary digits, actually) that limits the length of number that can be represented by such a data type. The
float
type has a limit of approximately 7 decimal digits (e.g. 3.141593); thedouble
type is limited to 14 (e.g. 3.1415926535898); and thereal
type has a similar limit (slightly more than that ofdouble
).Adding exceedingly small numbers to a floating-point value will therefore result in those digits being lost. Watch what happens when we add the following two float values together:
Both
a
andb
are valid float values and retain approximately 7 digits of precision apiece in isolation. But when added, only the frontmost 7 digits are preserved because it's getting shoved back into a float:So
c
ends up equal toa
because the finer digits of precision from the addition ofa
andb
get whacked off.Here's another explanation of the concept, probably much better than mine.
The answer to this problem is arbitrary-precision arithmetic. Unfortunately, support for arbitrary-precision arithmetic is not in CPU hardware; therefore, it's not (typically) in your programming language. However, there are many libraries that support arbitrary-precision floating-point types and the math you want to perform on them. See this question for some suggestions. You probably won't find any D-specific libraries for this purpose today, but there are plenty of C libraries (GMP, MPFR, and so on) that should be easy enough to use in isolation, and even more so if you can find D bindings for one of them.
如果您需要一个使用本机类型运行的解决方案,您应该能够通过尝试始终添加相似大小的数字来获得合理的结果。一种方法是计算级数的前 X 项,然后用总和重复替换两个最小的数字:(
最小堆会使速度更快一些。)
If you need a solution that will run using the native types you should be able to get reasonable results by trying to always add numbers of similar magnitude. One way to do this is to compute the first X terms of the series, and then repeatedly replace the two smallest numbers with there sum:
(A min heap would make this a bit faster.)
正如已经提到的,你需要使用一些第三方多精度浮点运算库(我认为Tango或Phobos只有一个用于任意长度整数运算的模块)。
dil 是一个使用 MPFR 的 D 项目。您应该在那里找到绑定。
As already mentioned you need to use some third-party multi-precision floating-point arithmetic library (I think Tango or Phobos only has a module for integer arithmetic of arbitrary length).
dil is a D project that uses MPFR. You should find bindings there.