打印双精度浮点数

printing double precision floating point numbers

我试图在字符串中表示双精度数,为此我使用了 grisu 的算法,您可以在这里查看:https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf

我已经完成了,显然正在工作,我的问题是在与高精度的 printf 输出进行比较时出现的,类似这样的事情:

double u = 1, t = 3;
double co = u/t;
printf("%.100f", co);

产出

0.3333333333333333148296162562473909929394721984863281250000000000000000000000000000000000000000000000

通过grisu的算法可以得到:

3333333333333333e-16

什么是逻辑,因为您可以使用 double 获得的最大精度是 21 位数字,您可以在“5.3 C 实现”(第 6 页)的 PDF 中阅读。那么如果我的最大精度是这个,或者哪个算法正在使用 printf 来获得这个精度,我该如何获得其余的?

[that] printf 的输出是错误的精度,因为它告诉您二进制数以十进制形式呈现时的精确值,就好像该二进制数在结束,当我们知道数字可能首先以十进制开始时。

浮点运算的一个基本原理,特别是在 IEEE 754 标准中指定的,是浮点数据精确地 表示一个特定的数字。

对浮点数执行运算时,精确的数学结果可能无法以浮点格式表示。在这种情况下,操作 return 是根据某种规则的最接近的可表示数字(通常舍入到最近的偶数位,但有时舍入到+无穷大、舍入到-无穷大、舍入到零或舍入到奇数)。因此,浮点运算中的运算可能return近似结果,但数字是精确的。

在您的示例中,将一除以三得到的浮点数正好是 0.333333333333333314829616256247390992939472198486328125。这是因为数学结果恰好是⅓,但不能用二进制浮点数表示,而上面显示的数字是最接近的可以表示的值,所以是结果。

使用转换说明符 %.100f 调用 printf 请求将此二进制浮点值转换为十进制。这是一个数学运算,将二进制浮点数转换为十进制的数学结果为“0.333333333333333314829616256247390992939472198486328125”。由于您告诉 printf 使用 100 个数字,它有足够的数字来产生准确的结果,所以它确实如此。

(这表明您使用的是高质量的 printf 实现。某些实现无法正确执行此操作。)

您引用的 Florian Loitsch 的论文提供了将二进制浮点值转换为足够十进制数字的算法,该值可以与相邻的浮点值区分开来。它通常不会生成足够的十进制数字来显示确切的值。例如,在具有两位数的 base-3 浮点数中,我们可以表示数字 0、1/9、2/9、3/9、4/9 等。在这种情况下,如果值为 4/9 (.4444...),则打印“.4”足以将该值与 .3333... 和 .5555... 区分开来,但它不能准确表示该值。 Loitsch 的算法只产生足够的数字来区分值,通常不足以显示精确的数学值。

(Loitsch 的论文还讨论了算法产生区分值的最短结果的频率——刚好足以完成工作的数字。)

关于基数之间转换的经典论文是 David M. Gay 的Correctly Rounded Binary-Decimal and Decimal-Binary Conversions