Dart,float for 循环会导致奇怪的结果
Dart, float for loop will cause strange result
for(int i=0; i<10; i++) {
priceValue.add(54.99 + i*5);
print(54.99 + i*5);
}
结果:
js_primitives.dart:30 54.99
js_primitives.dart:30 59.99
js_primitives.dart:30 64.99000000000001
js_primitives.dart:30 69.99000000000001
js_primitives.dart:30 74.99000000000001
js_primitives.dart:30 79.99000000000001
js_primitives.dart:30 84.99000000000001
js_primitives.dart:30 89.99000000000001
js_primitives.dart:30 94.99000000000001
js_primitives.dart:30 99.99000000000001
是什么导致 00000000001
出现?
这就是双数的工作原理。在使用与 Dart 相同的双打的其他语言中,您会得到相同的结果(它们被标准化为 IEEE-754 64-bit floating point numbers)。
症结在于,例如89.99不能用双精度精确表示。双打是 binary 数字,最多有 53 个有效位。
在二进制中,89.99 没有有限表示,就像 1/3 不能有限地写成十进制数一样(0.3333333 .... 精确值永远不够)。
只有有限数量的 double 值,分布在 double 覆盖的范围内。因此,当您尝试将 "real" 数字转换为双精度数时,计算机会四舍五入到与原始数字最接近的 双精度值。
即使是 54.99 也不准确。 54.99
的实际双精度值是最接近数学数字 54.99(又名 5499/100)的 double:
54.99000000000000198951966012828052043914794921875
然后将 35 添加到该值,这又不能表示为双精度,并且双精度硬件会选择最接近该值的双精度:
89.990000000000009094947017729282379150390625
由于原始 54.99 的不精确性,这实际上与只写 89.99
时选择的双精度不同,即:
89.9899999999999948840923025272786617279052734375
将双精度型转换为字符串时,选择表示的算法实际上很聪明。它选择 最短 十进制表示形式,其中数值将四舍五入为原始双精度值。
因此,由于 54.99 + 35
与 89.99
不同,因此它们需要具有不同的字符串表示形式。字符串 89.99
显然是为后者取的,所以 54.99 + 35
需要更多的数字来区分自己。这就是尾随 00000000000001
的来源。
所以,简而言之,这就是双打所做的。在使用相同双精度类型的大多数其他语言中,相同的计算将给出相同的结果。
for(int i=0; i<10; i++) {
priceValue.add(54.99 + i*5);
print(54.99 + i*5);
}
结果:
js_primitives.dart:30 54.99
js_primitives.dart:30 59.99
js_primitives.dart:30 64.99000000000001
js_primitives.dart:30 69.99000000000001
js_primitives.dart:30 74.99000000000001
js_primitives.dart:30 79.99000000000001
js_primitives.dart:30 84.99000000000001
js_primitives.dart:30 89.99000000000001
js_primitives.dart:30 94.99000000000001
js_primitives.dart:30 99.99000000000001
是什么导致 00000000001
出现?
这就是双数的工作原理。在使用与 Dart 相同的双打的其他语言中,您会得到相同的结果(它们被标准化为 IEEE-754 64-bit floating point numbers)。
症结在于,例如89.99不能用双精度精确表示。双打是 binary 数字,最多有 53 个有效位。 在二进制中,89.99 没有有限表示,就像 1/3 不能有限地写成十进制数一样(0.3333333 .... 精确值永远不够)。
只有有限数量的 double 值,分布在 double 覆盖的范围内。因此,当您尝试将 "real" 数字转换为双精度数时,计算机会四舍五入到与原始数字最接近的 双精度值。
即使是 54.99 也不准确。 54.99
的实际双精度值是最接近数学数字 54.99(又名 5499/100)的 double:
54.99000000000000198951966012828052043914794921875
然后将 35 添加到该值,这又不能表示为双精度,并且双精度硬件会选择最接近该值的双精度:
89.990000000000009094947017729282379150390625
由于原始 54.99 的不精确性,这实际上与只写 89.99
时选择的双精度不同,即:
89.9899999999999948840923025272786617279052734375
将双精度型转换为字符串时,选择表示的算法实际上很聪明。它选择 最短 十进制表示形式,其中数值将四舍五入为原始双精度值。
因此,由于 54.99 + 35
与 89.99
不同,因此它们需要具有不同的字符串表示形式。字符串 89.99
显然是为后者取的,所以 54.99 + 35
需要更多的数字来区分自己。这就是尾随 00000000000001
的来源。
所以,简而言之,这就是双打所做的。在使用相同双精度类型的大多数其他语言中,相同的计算将给出相同的结果。