我试图回答这个问题:编写一个函数 print_dig_float(float f) 打印 float 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
问题是,正如您在上面看到的,甚至在我对它进行任何操作之前,计算机就任意更改了数字末尾的小数位。这个问题不知道是我的错还是电脑的错。
最佳答案
根据 C 2018 5.2.4.2.2, float 用符号、某个指数的固定基数以及由该基数中的数字组成的数字表示。最常见的是,二作为基数。
当基数为二时,23432.214122 不能用 float 表示,因为每个可表示的数字都必然是基数的幂(可能是负幂)的某个整数倍。 23432.214122 不是 ½、¼、⅛、1/24、1/25 或任何其他 2 的幂的倍数。
当 23432.214122
在源代码中使用时,它被转换为可表示的值。在良好的 C 实现中,使用最接近的可表示值,但 C 标准允许使用最接近的较大值或最接近的较小值的可表示值。除此之外,出现的数字不是任意的;它们是数学的结果。
当 IEEE-754 binary32 用于 float
时,最接近 23432.214122 的可表示值正好是 23432.21484375。
因为,当 C 实现对 float 使用基数 2 时, float 只有二进制数字,没有十进制数字。尝试从没有十进制数字的事物中提取十进制数字通常没有意义。可以确定原始数字中的十进制数字,直至达到受浮点格式影响的某个限制。但是,“23432.214122”的位数太多,无法使用 32 位浮点类型执行此操作。对于 64 位类型,如通常用于 double
,您可以恢复原始数字,前提是您知道有多少位十进制数字开始。如果没有该信息,通常不可能恢复原始数字 - 正如您所见,尾随数字会有所不同,并且 float 本身没有指示差异开始的位置。
关于c - 当 float 是函数的实际参数时,为什么我的计算机会任意更改 float 末尾的小数位?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59212866/