C语言 如果float有6位精度,为什么我们可以用printf显示超过6位的浮点数?

hmtdttj4  于 2023-05-22  发布在  其他
关注(0)|答案(3)|浏览(186)

让我们考虑以下代码:

#include <stdio.h>
int main()
{
    float x = 0.33;
    printf("%.100f",x);

    return 0;
}

如果float的精度是6位,那么printf怎么可能显示6位以上的数字呢?

u91tlkcl

u91tlkcl1#

您尝试将小数0.33转换为float。但是,像大多数十进制小数一样,数字0.33不能用float类型内部使用的二进制表示形式精确表示。你能得到的最接近的是二进制分数0.0101010001111010111000011。这个分数,如果我们把它转换回十进制,正好是0.3300000131130218505859375。
在十进制中,如果我告诉你你有7位有效数字,你试图表示数字1/3 = 0.333...,你期望得到0.333333300000。也就是说,您希望得到一些与原始数字匹配的有效数字,后面是0,因为没有足够的有效数字。和二进制分数的工作方式相同:对于类型float,二进制小数总是有24位的有效位,后面(如果你喜欢的话)是任意数量的二进制0。
当我们将二进制数转换回十进制数时,我们得到大约7位数,与我们认为的十进制数相匹配,后面不是零,而是看起来像随机数字的数字。例如,1/3作为二进制float0.0101010101010101010101011000000000(注意24个有效位),当转换为十进制时是0.333333343267440795898437500000(注意7个准确数字)。
当你听到类型float有大约7位有效数字时,这并不意味着你会得到原始数字的7位数字,后面跟着0。这意味着你会得到 * 大约 * 7个原始数字(但可能是6个,也可能是8个或9个或更多),后面跟着一些数字,这些数字可能与你的原始数字不匹配,但也不全是0。但这实际上并不是一个问题,特别是如果(正如推荐和正确的那样)您将这个数字打印出来,四舍五入到一个有用的数字。当它可能是一个问题(虽然这出现了很多)是当你打印出一个没有用的数字,格式像%.100f,你看到一些奇怪的数字,不全是0,这让你困惑,就像这里一样。
类型floatdouble在内部使用二进制表示的事实导致了像这样的无尽的惊喜。表示是二进制的并不奇怪(我们都知道计算机用二进制做任何事情),但是二进制 * 分数 * 无法准确表示我们习惯的十进制分数,现在这真的很令人惊讶。请参阅标准SO问题Is floating point math broken?了解更多信息。

ercv8c1e

ercv8c1e2#

“如果float有6位数的精度...”-->是一个弱前提。
常见的float'没有6位的 decimal 精度,而是24位的 binary 精度。
如何用printf(?)
当以十进制打印一个二进制浮点数时,每个二进制数字贡献一些2的幂,如...,16,8,4,2,1,0.5,0.25,0.125,0.0625,...
这些2的幂的总和可以容易地超过6个十进制数字。
在极端情况下,FLT_TRUE_MIN通常具有以下精确值:

0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125

小数点后9位有效数字很少有比这更重要的。

km0tfn4u

km0tfn4u3#

如果float有6位精度,为什么我们可以用printf显示超过6位的浮点数?
float的每个定义没有6位精度。您已经选择显示比实现可能提供的数字更多的数字-它提供了。
为什么我们可以用printf显示超过6位的浮点数?
你可以告诉程序显示float/double/long double中的任何内容,它仍然是一个近似值。

  • 显示 * 此类变量的当前内容最好在调试时完成。

比较:https://en.wikipedia.org/wiki/IEEE_754

相关问题