首页 > 解决方案 > 浮点的printf如何不打印浮点的正确值

问题描述

所以我一直在尝试制作自己的 printf,但现在我卡在了 %f 上。我遇到的问题是,当我给它一个浮点数时,我不知道 printf 在后台做了什么:f = 1.4769996它打印 1.477000。但是当我给f = 1.4759995它打印值 1.475999

float f = 1.4769996;
printf("%f\n", f); // 1.477000

f = 1.4759995;
printf("%f\n", f); // 1.475999

我想到的是 printf 最后看到了 5 并且它添加了一个但在第二个示例中不起作用。

这个浮点数背后的逻辑是什么?

标签: cfloating-pointprintf

解决方案


您的 C 实现可能使用 IEEE-754 binary32 和 binary64 格式floatdouble. 鉴于此,float f = 1.4769996;导致设置f为 1.47699964046478271484375,并f = 1.4759995;导致设置f为 1.47599947452545166015625。

那么很容易看出,将1.476999 64046478271484375四舍五入到小数点后六位得到1.477000(因为下一位是6,所以我们四舍五入),将1.475999 47452545166015625四舍五入到小数点后六位得到1.475999(因为下一个数字是 4,所以我们向下取整)。

处理浮点数时,重要的是要了解每个浮点值准确地表示一个数字(除非它是非数字 [NaN] 编码)。当您1.4769996在源代码中编写时,它会转换为可在double. 当您将其分配给 afloat时,它会转换为可在 中表示的值float。对浮点对象的操作表现得好像该对象具有它所代表的值,而不是它的值是您在源代码中编写的数字。

为了提供更多详细信息,C 标准要求(在 C 2018 7.21.6.1 13 中)f如果请求的位数最多为 ,则格式必须正确舍入DECIMAL_DIGDECIMAL_DIG是实现支持的最宽浮点格式的小数位数,以便将该格式中的任何数字转换为具有DECIMAL_DIG有效十进制数字的数字并返回浮点格式产生原始值(5.2.4.2.2 12 )。DECIMAL_DIG必须至少为 10。如果要求的数字多于DECIMAL_DIG数字,C 标准允许在四舍五入中留出一些余地。但是,高质量的 C 实现将按照 IEEE-754 的规定正确四舍五入(到具有所请求位数的最接近的数字,平局有利于偶数低位)。


推荐阅读