Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Dart 省道舍入误差_Dart - Fatal编程技术网

Dart 省道舍入误差

Dart 省道舍入误差,dart,Dart,这样做打印(0.3-0.2)将打印0.09999999998 我知道浮点运算对于二进制处理器来说是不可能正确的,但我希望Dart内置的东西至少能消除舍入误差 让上面的内容显示0.1需要进行一些来回转换,我不希望这样做: print(num.parse((0.3 - 0.2).toStringAsPrecision(8))); -> 0.1 我有什么办法不疯狂地使用小数?Dart中有没有内置的东西可以帮助您实现这一点?似乎只有一个库可以实现上述功能:?大多数人做的是乘法、算术、取整,然后

这样做
打印(0.3-0.2)将打印
0.09999999998

我知道浮点运算对于二进制处理器来说是不可能正确的,但我希望Dart内置的东西至少能消除舍入误差

让上面的内容显示0.1需要进行一些来回转换,我不希望这样做:

print(num.parse((0.3 - 0.2).toStringAsPrecision(8)));

-> 0.1

我有什么办法不疯狂地使用小数?Dart中有没有内置的东西可以帮助您实现这一点?似乎只有一个库可以实现上述功能:?

大多数人做的是乘法、算术、取整,然后除以所需的精度

final precision = 10;


final difference = (0.3 * precision) - (0.2 * precision);
final result = difference.round() / precision; // will give you 0.1

.round()
确保在返回到所需精度之前,数学运算后的任何尾随小数都会被舍入。

您可以通过以下方式将值舍入到十的倍数(或任何其他数字):

然后可以对初始值或最终结果执行此操作:

int precision = 10;
final result = roundTo(0.3 - 0.2, precision);
// or inlined:
final result = ((0.3 - 0.2) * precision).round() / precision; 
这确保了计算是在原始值上完成的,并且只对最终结果进行四舍五入

如果您知道您的输入值都具有相同的比例,那么可以按照@brian gorman的建议,首先对值进行比例调整,然后在最后对结果进行四舍五入和向下比例调整。为此,我建议尽早对输入值进行四舍五入,这样计算就不会累积不精确性。 (这对于一次减法并不重要,但对于一次更复杂的计算,可能会有影响)

请注意:您看到的结果不是舍入错误,而是IEEE-754定义的64位浮点数的正确结果

您将在使用普通双精度的任何其他语言(包括JavaScript和Java)中看到相同的结果。
0.3-0.2
的结果不是表示为
0.1
的双精度。它是一个不同的数字,因此它必须具有不同的
toString
表示形式

0.1、0.2或0.3都不能精确表示为双精度。实际值为:

  • 0.1
    :0.10000000000000055115123125782702118158340451015625
  • 0.2
    :0.2000000000011102230246256540423631668090908203125
  • 0.3
    :0.29999999999988897769753748434595763683319091796875
  • 0.3-0.2
    :0.099999999997779553950749686919152736663818359375
因此,当您编写语法
0.3
0.2
时,实际上是在指定上面的精确双精度值

结果就是这样,因为0.3-0.2的精确数学计算是

  0.299999999999999988897769753748434595763683319091796875
- 0.200000000000000011102230246251565404236316680908203125 
= 0.099999999999999977795539507496869191527366638183593750

结果是一个精确的双倍值。所以结果是0.09999。。。正是“0.3”和“0.2”之间的差值,因此是正确的减法结果。(错误是假设您实际上有0.3和0.2作为值,但您从未这样做)。它与0.1表示的数字也不相同。

感谢您提供了详尽的答案。你能澄清一下你所说的
0.0999999
是什么意思吗?我很欣赏提前四舍五入的建议。在以前的一个项目中,我们努力消除潜入的、难以消除的舍入错误。Tbh。我仍然把它们称为舍入误差,而不是不精确性,因为当一个人写0.3-0.2时,潜在的假设是写的值是正在计算的值,而不是潜在的IEEE-754表示。不过,为了做出更好的决策,了解引擎盖下发生的事情仍然很有价值。无论如何,非常感谢你的回答!是否存在舍入误差可能是一个哲学上的讨论。可以说,语言绕过代码> 0.2 /代码>到最近的双值,并且可以认为是一个错误。或者你也可以定义语法
0.2
表示这个双值,并且假设它是数学值2/10是一个(人类的假设)错误。波塔托,波塔托,结果是一样的,我们这些可怜的人只是在这里指导计算机做什么。从定义上讲,计算机总是正确的,只是指令可能用于错误的东西。:)旁白:永远不要用浮点计算货币。记住《超人4》和《办公空间》:)
final difference = (0.3 * precision).round() - (0.2 * precision).round();
final result = difference / precision;
  0.299999999999999988897769753748434595763683319091796875
- 0.200000000000000011102230246251565404236316680908203125 
= 0.099999999999999977795539507496869191527366638183593750