因此,执行print(0.3 - 0.2);
将打印0.09999999999999998
。
我知道二进制处理器无法正确执行浮点运算,但是我希望Dart内置一些东西,至少可以消除舍入错误。
获取上面的内容以显示0.1会带来一些来回转换,而我不希望这样做:
print(num.parse((0.3 - 0.2).toStringAsPrecision(8)));
-> 0.1
对于不疯狂使用小数,我有哪些选择? Dart内置了什么功能可以帮助解决此问题?似乎只有一个库可以完成上述操作:https://pub.dev/packages/decimal?
答案 0 :(得分:1)
大多数人要做的是相乘,算术,四舍五入,然后除以所需的精度
final precision = 10;
final difference = (0.3 * precision) - (0.2 * precision);
final result = difference.round() / precision; // will give you 0.1
.round()
确保在返回到所需的精度之前,对四舍五入后的小数进行四舍五入。
答案 1 :(得分:1)
您可以通过以下方式将值四舍五入到十(或任何其他数字)的倍数:
double roundTo(double value, double precision) => (value * precision).round() / precision;
然后您可以对初始值或最终结果执行此操作:
int precision = 10;
final result = roundTo(0.3 - 0.2, precision);
// or inlined:
final result = ((0.3 - 0.2) * precision).round() / precision;
这可以确保对原始值进行计算,而您只舍入最终结果。
如果您知道输入值都具有相同的小数位数,则可以按照@ brian-gorman的建议进行操作并先缩放这些值,然后最后对结果进行四舍五入和缩减。对于这种用途,我建议对输入值进行四舍五入,以免计算不准确。 (这对于单次减法无关紧要,但是对于更复杂的计算,则可能如此)。
final difference = (0.3 * precision).round() - (0.2 * precision).round();
final result = difference / precision;
记录:您看到的结果不是舍入错误,而是正确结果-对于IEEE-754定义的64位浮点数。
您将看到使用普通双精度语言的任何其他语言的相同结果,包括JavaScript和Java。 0.3 - 0.2
的结果不是表示为0.1
的双精度值。它是一个不同的数字,因此它必须具有不同的toString
表示形式。
0.1、0.2或0.3均不能精确表示为double。实际值为:
0.1
:0.1000000000000000055511151231257827021181583404541015625 0.2
:0.200000000000000011102230246251565404236316680908203125 0.3
:0.299999999999999988897769753748434595763683319091796875 0.3 - 0.2
:0.09999999999999997779553950749686919152736663818359375 因此,当您编写语法 0.3
和0.2
时,实际上就是在指定上面的精确double值。
结果变为原来的样子,因为精确的数学计算为0.3-0.2是
0.299999999999999988897769753748434595763683319091796875
- 0.200000000000000011102230246251565404236316680908203125
= 0.099999999999999977795539507496869191527366638183593750
,结果是精确的双精度值。因此,结果0.09999 ...恰好是“ 0.3”和“ 0.2”之间的差,因此是减法的正确结果。 (错误是假设您实际上拥有0.3和0.2作为值,但从未如此)。它也与由0.1表示的数字不相同。