C语言 如何在浮点运算中舍入结果



我写了这段代码,它只是简单地对 n 个数字的列表求和,以练习浮点运算,我不明白这一点:

我正在使用浮点数,这意味着我有 7 位精度,因此,如果我执行运算 10002*10002=100040004,数据类型 float 的结果将是 100040000.000000,因为我丢失了超过 7 位的任何数字(程序仍然知道指数,如此处所示)。

如果此程序中的输入是

3
10000
10001
10002

但是,您将看到,当该程序计算 30003*30003=900180009我们有 30003*30003=900180032.000000

我知道这 32 的出现是因为我正在使用 float,我的目标不是使程序更精确,而是了解为什么会发生这种情况。为什么是 900180032.000000 而不是 900180000.000000?为什么这个十进制噪声(32)出现在30003 * 30003而不是10002 * 10002中,即使数字的大小相同?谢谢你的时间。

#include <stdio.h>
#include <math.h>
#define MAX_SIZE 200

int main() 
{
int numbers[MAX_SIZE]; 
int i, N;
float sum=0;
float sumb=0;
float sumc=0;
printf("introduce n" );
scanf("%d", &N);
printf("write %d numbers:n", N);
for(i=0; i<N; i++)
{
scanf("%d", &numbers[i]);
}
int r=0;
while (r<N){
sum=sum+numbers[r];
sumb=sumb+(numbers[r]*numbers[r]); 
printf("sum is %fn",sum);
printf("sumb is %fn",sumb);
r++;
}
sumc=(sum*sum);
printf("sumc is %fn",sumc);
}

如下所述,将 10,002 乘以 10,002 的计算结果必须是 8 的倍数,将 30,003 乘以 30,003 的计算结果必须是 64 的倍数,因为数字的大小和可用于表示它们的位数。虽然您的问题询问的是"十进制噪声",但这里不涉及十进制数字。结果完全是由于四舍五入到2的幂的倍数。(您的 C 实现似乎对二进制浮点使用通用的 IEEE 754 格式。

将 10,002乘以 10,002 时,计算结果必须是 8 的倍数。我将在下面解释原因。数学结果为 100,040,004。最接近的 8 的倍数是 100,040,000 和 100,040,008。它们与确切结果相去甚远,用于打破关系的规则选择偶

数倍数(100,040,000 是 12,505,000 的八乘以偶数,而 100,040,008 是 12,505,001 的八倍,奇数)。许多 C 实现使用 IEEE 754 32 位基本二进制浮点进行float。在这种格式中,数字表示为整数M乘以 2e的幂。整数M的星等必须小于 224。指数e可以从 −149 到 104。这些限制来自用于表示整数和指数的位数。

因此,对于某些 M 和某些e,此格式的所有float值都具有值M2e。格式中没有十进制数字,只有一个整数乘以 2 的幂。

考虑数字 100,040,004。 我们可以使用的最大M是 16,777,215 (224−1)。这还不够大,我们可以将 100,040,004 写为M• 20。所以我们必须增加指数。即使有 22,我们能得到的最大值也是 16,777,215 • 22= 67,108,860。所以我们必须使用 23。这就是为什么在这种情况下,计算结果必须是 8 的倍数。

因此,为了在float中生成 10,002•10,002 的结果,计算机使用 12,505,000 • 23,即 100,040,000。

在 30,003•30,003 中,结果必须是 64 的倍数。确切结果是 900,180,009。2 5是不够的,因为 16,777,215•25是 536,870,880。所以我们需要 26,即 64。64 的两个最接近的倍数是 900,179,968 和 900,180,032。在这种情况下,后者更近(23 个距离与 41 个距离),因此选择了它。

(虽然我将格式描述为整数乘以 2 的幂,但它也可以描述为二进制数字,基数点之前有一个二进制数字,之后有 23 个二进制数字,并调整指数范围以补偿。这些在数学上是等价的。IEEE 754标准使用后一种描述。教科书可能会使用前一种描述,因为它使分析某些数值性质更容易。

浮点运算以二进制完成,而不是十进制。

浮点数实际上有 24 个二进制位的精度,其中 1 个是符号位,23 个称为有效位。这将转换为大约7 个十进制数字的精度。

900180032,您正在查看的数字已经有 9 位数字长,因此最后两位数字(32位)可能是错误的。像算术一样的舍入是在二进制中完成的,只有将事物分解为二进制才能看到四舍五入差异的原因。

900180032 =110101101001111010100001000000

900180000 =110101101001111010100000100000

如果你从每个数字的前 1 到最后 1 计数(我加粗的部分),那就是存储数字需要多少有效位。 900180032只需要 23 个有效位来存储,而 900180000 需要 24 个有效位,这使得 900180000 是一个不可能存储的数字,因为浮点数只有 23 个有效位。 900180032是最接近正确答案的数字, 900180009,浮子可以存储。

在另一个示例中

100040000 =101111101100111110101000000

100040004 =101111101100111110101000100

正确答案,100040004有 25 个有效位,对于浮点数来说太多了。具有 23 个或更低有效位的最接近的数字是 10004000,它只有 21 个有效位。

有关浮点运算工作的更多信息,请尝试此处 http://steve.hollasch.net/cgindex/coding/ieeefloat.html

最新更新