打印双精度浮点数

时间:2018-01-23 20:43:55

标签: c algorithm floating-point double ieee-754

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

我完成了它,并且显然正在工作,我的问题来自于与printf输出相比具有高精度,类似的东西:

SEVERITY_ERROR

输出

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

使用grisu算法,我可以获得以下内容:

0.3333333333333333148296162562473909929394721984863281250000000000000000000000000000000000000000000000

什么是逻辑,因为双倍的最大精度是21位数,因为您可以在PDF中阅读" 5.3 C实施" (第6页)。那么如果我的最大精度是这个,或者哪个算法使用printf来获得这个精度,我怎么能得到其余的呢?

2 个答案:

答案 0 :(得分:3)

浮点运算的基本原理,特别是IEEE 754标准中规定的,浮点数据表示完全一个特定数字。

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

在您的示例中,将1除以3​​会产生一个浮点数,正好是0.333333333333333314829616256247390992939472198486328125。这是因为数学结果恰好是⅓,但这在二进制浮点中是不可表示的,并且上面显示的数字是可表示的最接近的值,因此这就是结果。

使用转换说明符printf调用%.100f请求将此二进制浮点值转换为十进制。这是一个数学运算,将二进制浮点值转换为十进制的数学结果将是“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的正确舍入的二进制 - 十进制和十进制 - 二进制转换

答案 1 :(得分:-2)

[that] printf的输出是一个错误的精度,从某种意义上说它是告诉你二进制数的精确值,当用十进制呈现时,好像那个二进制数在末尾有无限数量的0位,当我们知道这个数字可能首先以小数开头。