浮点数精度

时间:2020-09-13 09:52:59

标签: c floating-point precision

我观看了计算机迷的视频https://www.youtube.com/watch?v=PZRI1IfStY0,并尝试理解浮点不精确度的概念。我知道0.1不能精确地以二进制形式表示。 我尝试自己做实验,并使用浮点类型变量存储数字4.2。

这些是代码:

htmlString.getElementById("someid").value

输出为:

#include <stdio.h>

int main(void)
{
    float m = 4.2;
    printf("%f\n", m * 1);
    printf("%f\n", m * 10);
    printf("%f\n", m * 100);
    printf("%f\n", m * 1000);
}

为什么只将4.2乘以100不正确?

1 个答案:

答案 0 :(得分:2)

首先,当使用%f进行转换时,printf将数字四舍五入到小数点后六位。要查看这种情况下的完整值,可以使用%.20f

#include <stdio.h>


int main(void)
{
    float m = 4.2;
    printf("%.20f\n", m * 1);
    printf("%.20f\n", m * 10);
    printf("%.20f\n", m * 100);
    printf("%.20f\n", m * 1000);
}

输出:

4.19999980926513671875
42.00000000000000000000
419.99996948242187500000
4200.00000000000000000000

要了解正在发生的事情,请考虑m的实际值。在您的C实现中,float是使用24位有效数字(浮点数的小数部分)实现的。通常将其描述为24位二进制数,在第一位后带有小数点(小数点的通用版本),例如1.00001100110011001100110 2 。使用符号和指数,浮点形式为+1.00001100110011001100110 2 •2 2

但是,通过相应地调整指数,我们也可以将有效位数缩放为小于2 24 的整数。 +1.000011001100110011001100 2 •2 2 = +100001100110011001100110 2 •2 -21 。以十进制表示的100001100110011001100110 2 为8,808,038,2 −21 为1 / 2,097,152。并且8,808,038 / 2,097,152 = 4.19999980926513671875。这种使用小于2 24 的整数表示形式在数学上等同于带小数点的形式,但是它使我们更容易看到一些舍入效果,如下所示。

如果使用普通的实数算法乘以10,结果将为88,080,380 / 2,097,152 = 88,080,380 / 2 21 。但是,该分子不适合C实现使用的float格式的24位。我们必须进行调整以使其低于2 24 = 16,777,216。通过调整指数进行调整,该指数乘以或除以2的幂。我们可以将指数调整三倍,并将分子除以2 3 ,得到11,010,047.5 / 2 18 。但是现在分子不是整数。为了使其适应格式,将其舍入为最接近的整数。 11,010,047和11,010,048与11,010,047.5相等。平局的规则是使用带有偶数低位的选择,因此使用11,010,048。

因此m * 10的结果为11,010,048 / 2 18 = 11,010,048 / 262,144 = 42。

现在考虑乘以100。实数结果为880,803,800 / 2 21 。为了使分子低于16,777,216,我们将指数除以6,将分子除以64。结果为13,762,559.375 / 2 15 。再次将分子四舍五入为整数,得到13,762,559 / 2 15 。请注意,在这种情况下,我们碰巧是舍入而不是舍入。碰巧分数落在½以下,所以我们四舍五入。 13,762,559 / 2 15 = 13,762,559 / 32,768 = 419.999969482421875。

这里发生的是乘以10-1、10、100、1000的幂(二进制:1、1010 2 ,1100100 2 ,1111101000) 2 )-在这些分数中产生各种结果。由于我们从略低于4.2(4.19999980926513671875)的数字开始,因此在进行四舍五入时,结果达到4.2的倍数。如果进行四舍五入,则不会。