提问人:Udesh 提问时间:4/20/2023 最后编辑:Udesh 更新时间:4/21/2023 访问量:56
程序给出不准确的值
Program giving inaccurate value
问:
下面的程序计算 262 + 261 + 260 + ... + 21 + 20。
使用类型存储:double
sum
double sum = 0;
for (int i = 0; i < 63; i++) {
sum += pow(2.0, i);
// print("i : $i sum : $sum");
}
print(sum);
输出:
9223372036854776000.0
很明显,答案应该是一个数字,但 is : 这是一个数字。odd
sum
9223372036854776000.0
even
当我将总和更改为 int 数据类型时,它给出了准确的结果:
使用类型存储:int
sum
int sum = 0;
for (int i = 0; i < 63; i++) {
sum += pow(2.0, i).toInt();
//print("i : $i sum : $sum");
}
print(sum);
输出:
9223372036854775807
当数据类型为 double 时,为什么求和会产生错误的结果?
答:
3赞
Mark Adler
4/20/2023
#1
因为 a 的有效位只有 53 位有效位,而你的数字有 63 位。double
52 存储在主有效字段中,其中 53 位二进制分数的前导位为隐式。1
评论
2赞
Mark Adler
4/20/2023
尾数有 52 位存储,带有隐含的前导位。因此,如果计算隐含位,则可以将其视为 53。1
1赞
Eric Postpischil
4/20/2023
IEEE 754 标准使用的术语是“significand”而不是“mantiissa”。浮点表示的分数部分是有效。“尾数”是对数分数部分的旧术语。有效数是线性的;添加到有效值并添加到所表示的数字中。尾数是对数的;将尾数相加会使所代表的数字成倍增加。
3赞
jamesdlin
4/21/2023
@Udesh 请注意,打印并不一定告诉您有关有效位数的任何信息。位在有效和控制精度,而不是大小。这两个表达式只需要一个有效位。根据用于将二进制浮点数转换为十进制字符串的算法,这两个表达式最终可能会打印相同的内容¹。更好的测试是检查。1 << 53
pow(2.0, 53)
var x = (1 << 53).toDouble(); print(x == x + 1);
1赞
jamesdlin
4/21/2023
¹ 例如,在我的系统上使用标准 C 库实现,打印相同的值(不包括尾随小数零)。Dart 碰巧打印不同的值,因为它的转换方式不同。int64_t x = 1; x <<= 62; printf("%"PRId64"\n", x); printf("%f\n", (double) x);
double
String
1赞
jamesdlin
4/21/2023
@Udesh 不,2^53 最多需要使用有效位的一位。它没有告诉你有效使用的位数。另一方面,2^53 - 1 将使用所有有效位。
评论