当前位置: 首页 > 知识库问答 >
问题:

浮点运算的结果如何舍入?

刘狐若
2023-03-14

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

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

如果此程序中的输入是

3
10000
10001
10002

然而,您将看到,当这个程序计算30003*30003=900180009时,我们得到了30003*30003=900180032.000000

我理解这个32出现是因为我正在使用浮点数,我的目标不是让程序更精确,而是理解为什么会发生这种情况。为什么它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 %f\n",sum);
    printf("sumb is %f\n",sumb);
    r++;
}
sumc=(sum*sum);
printf("sumc is %f\n",sumc);
}

共有2个答案

钱嘉致
2023-03-14

浮点运算是用二进制而不是十进制完成的。

浮点数实际上有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

张翰海
2023-03-14

如下所述,10002乘以10002的计算结果必须是8的倍数,30003乘以30003的计算结果必须是64的倍数,这是由于数字的大小和可用于表示它们的位数。虽然您的问题是关于“十进制噪音”,但这里没有涉及十进制数字。结果完全是由于四舍五入到二的幂的倍数。(您的C实现似乎对二进制浮点使用通用IEEE 754格式。)

将10002乘以10002时,计算结果必须是8的倍数。我将在下面解释原因。数学结果为100040004。8的最接近倍数为100040000和100040008。它们与精确结果相差同样远,用于打破关系的规则选择偶数倍(100040000是8乘以12505000,是偶数,而100040008是8乘以12505001,是奇数)。

许多C实现使用IEEE 754 32位基本二进制浮点来实现浮动。在这种格式中,数字表示为整数M乘以2的幂2e。整数M的大小必须小于224。指数e可以从−149到104。这些限制来自用于表示整数和指数的位数。

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

考虑数字100040004。我们可以使用的最大M是16777215(224−1) 。这还不够大,我们无法将100040004写为M•2。所以我们必须增加指数。即使有2,我们能得到的最大值也是16777215•2=67108860。因此,我们必须使用23。这就是为什么在这种情况下,计算结果必须是8的倍数。

因此,为了在浮动中生成10,002 10,002的结果,计算机使用12,505,000 23,这是100,040,000。

在30003•30003中,结果必须是64的倍数。准确的结果是900180009。25是不够的,因为16777215•25是536870880。所以我们需要2,也就是64。最接近64的两个倍数是900179968和900180032。在这种情况下,后者更近(23比41),因此选择它。

(虽然我已经将格式描述为整数乘以二的幂,但也可以将其描述为一个二进制数字,在小数点之前有一个二进制数字,后面有23个二进制数字,并调整指数范围以进行补偿。这些在数学上是等效的。IEEE 754标准使用后一种描述。教科书可能使用前一种描述,因为它可以分析som数值特性的e更容易。)

 类似资料:
  • 问题内容: 我需要在Java中执行一些浮点运算,如下面的代码所示: 这是为了模拟Betfair Spinner小部件作为输出给出的值的范围。 Java中的浮点算术似乎引入了一些意外错误。例如,我得到2.180000000000001而不是2.18。浮点数有什么用,您不相信对它们执行的算术结果吗?我该如何解决这个问题? 问题答案: 如果您需要精确的十进制值,则应使用java.math.BigDeci

  • 我阅读关于浮点和舍入在浮点算术期间发生的错误。 我读了很多关于IEEE754单精度/双精度格式的文章。我知道有符号位、8(或)11位指数和23(或)52位有效位以及隐式前导位。 我也知道分母不是质因数2的实数不能完全表示,例如二进制中的0.1是0.0001100110011...... 我知道0.1 0.1 0.1不等于0.3,因为舍入误差的累积。 同样,0.5也可以用二进制格式表示,因为它是1/

  • 我将货币值作为浮动存储在mysql表中。 问题是,mysql正在向上或向下舍入数字。 例如,12345.68四舍五入为12345.7 如何停止此操作,或者是否应该使用更好的数据类型? 我希望将原始值保留在小数点后2位以内。

  • 问题是,每当我使用“System.out.printf(”%.2F\n“,BMI)”时,输出将四舍五入,而不是切断小数点的其余部分。下面是我的代码:

  • 对于这些代码行,我得到0作为输出,即它们都是相等的。现在,如果我理解正确,a b和c可能会存储稍微不同版本的真值.3因此,当做一个Float.compare(...)对这些值,我希望得到一个输出值,而不是0。为什么我把它们取为0?

  • 我有一个关于PostgreSQL 9.2中浮点数的新手问题。 有没有直接舍入浮点数的函数,即不需要先将数字转换为数字类型? 另外,我想知道是否有一个函数可以用任意的度量单位进行取整,例如精确到0.05? 首先将数字转换为十进制形式时,以下查询工作正常: 然而,我真正想要实现的是以下几点: 这当前给了我以下错误: 谢啦