C-打印浮点值-在转换为int时精度下降

C - Printing a float - loss of precision when casting to int

本文关键字:int 精度 转换 打印      更新时间:2023-10-16

我正在尝试制作一个函数,使我能够打印浮点值。现在,我遇到了两种奇怪的行为:有时,像1.3这样的值显示为1.2999999而不是1.300000,有时像1.234567这样的值则显示为1.2345672而不是1.2345670。

这是源代码:

int     ft_putflt(float f)
{
    int     ret;
    int     intpart;
    int     i;
    ret = 0;
    i = 0;
    intpart = (int)f;
    ft_putnbr(intpart);
    ret = ft_nbrlen(intpart) + 8;
    write(1, ".", 1);
    while (i++ < 7)
    {
        f *= 10;
        ft_putchar(48 + ((int)f % 10));
    }
    return (ret);
}

ft_putnbr是OK AFAIK。ft_putchar是对"write(1,&c,1)"的简单调用。

test values (value : output)
1.234567  : 1.2345672 (!)
1.2345670 : 1.2345672 (!)
1.0000001 : 1.0000001 OK
0.1234567 : 0.1234567 OK
0.67      : 0.6700000 OK
1.3       : 1.3000000 OK (fixed it)
1.321012  : 1.3210119 (!)
1.3210121 : 1.3210122 (!)

这一切对我来说似乎有点神秘……在向int投射时可能会失去精度?

是的,在处理浮点和int时会丢失精度。

如果两个浮点数的大小不同,并且都使用完整的精度范围(约为7位小数),那么是的,您将在最后几位看到一些损失,因为浮点数以(符号)(尾数)×2(指数)的形式存储。如果两个值有不同的指数,并且将它们相加,那么较小的值将减少到尾数中的较少数字(因为它必须适应较大的指数):

PS> [float]([float]0.0000001 + [float]1)
1

关于整数,一个正常的32位整数能够精确地表示不完全适合浮点的值。float仍然可以存储大约相同的数字,但不再精确。当然,这只适用于足够大的数字,例如超过24位的数字。因为浮点有24位精度,(32位)整数有32位,所以浮点仍然能够保留幅度和大多数有效数字,但最后几位可能不同:

PS> [float]2100000050 + [float]100
2100000100

这是使用有限精度数值表示方案所固有的。给定任何可以表示的数字,A,有一个数字是可以表示的大于A的最小数字,称之为B。A和B之间的数字不能精确表示,必须近似。

例如,让我们考虑使用六位十进制数字,因为这是一个更容易理解的系统作为起点。如果A是.333333,那么B是.33334。介于A和B之间的数字,例如1/3,无法精确表示。因此,如果你取1/3并将其与自身相加两次(或乘以3),你会得到.999999,而不是1。你应该预料到这种表述的局限性是不精确的。