首页 > 解决方案 > 当浮点数是函数的实际参数时,为什么我的计算机会任意更改浮点数末尾的小数位?

问题描述

我试图解决这个问题:编写一个函数 print_dig_float(float f),它打印浮点数 f 的每个数字的值。例如,如果 f 是 2345.1234,print_dig_float(f) 将连续打印数字 2、3、4、5、1、2、3 和 4 的整数值。

我所做的是:给定一个带有一些小数的数字,我尝试通过将其乘以 10 将数字向左移动(例如:3.45 -> 345)。之后,我通过取余数将每个数字存储在一个数组中并把它放在一个元素中。然后,我将它们打印出来。

所以我的程序是这样的:

#include <stdio.h>

void print_dig_float(float f);

int main(int argc, char const *argv[]) {

    print_dig_float(23432.214122);

    return 0;
}

void print_dig_float(float f) {

    printf("%f\n", f);

    int i = 0, arr[50], conv;

    //move digits to the left

    do {

        f = f * 10;
        conv = f;
        printf("%i\n", conv);

    } while (conv % 10 != 0);

    conv = f / 10;

    //store digits in an array

    while (conv > 1) {
        arr[i] = conv % 10;
        conv = conv / 10;
        i++;
    }

    for (int j = i - 1; j >= 0; j--) {
        printf("%i ", arr[j]);
    }

    printf("\n");

}

当我用数字测试它时:23432.214122,这就是我得到的(根据Linux终端):

23432.214844

234322

2343221

23432216

234322160

2 3 4 3 2 2 1 6

问题是,正如您在上面看到的,即使在我对它做任何事情之前,计算机也会任意更改数字末尾的十进制数字。我不知道这是我的错还是电脑的问题。

标签: cfloating-point

解决方案


根据 C 2018 5.2.4.2.2,浮点数用符号、某个指数的固定基数以及由该基数中的数字组成的数字表示。最常见的是,两个用作基础。

当基数为 2 时,23432.214122 不能用浮点数表示,因为每个可表示的数字都必须是基数的某个整数倍数(可能是负数)。23432.214122 不是 ½、¼、⅛、1/2 4、1/2 5或任何其他 2 的幂的倍数。

23432.214122源代码中使用时,将其转换为可表示的值。在良好的 C 实现中,使用最接近的可表示值,但 C 标准允许使用最接近的较大或最接近的较小值的可表示值。除此之外,出现的数字不是任意的;它们是数学的结果。

当 IEEE-754 binary32 用于 时float,最接近 23432.214122 的可表示值正好是 23432.21484375。

因为,当 C 实现使用以二为底的浮点数时,浮点数具有二进制数字而没有十进制数字。尝试从没有十进制数字的事物中提取十进制数字通常是没有意义的。可以确定原始数字中的十进制数字,直至受到浮点格式影响的某个限制。但是,“23432.214122”的位数太多,无法使用 32 位浮点类型执行此操作。使用 64 位类型,通常用于double,您可以恢复原始数字,前提是您知道有多少个十进制数字开头。如果没有这些信息,通常不可能恢复原始数字 - 正如您所看到的尾随数字会不同,并且浮点数本身没有指示差异开始的位置。


推荐阅读