浮点和避免舍入误差

时间:2017-01-29 22:09:42

标签: floating-point rounding rounding-error 8-bit

众所周知,浮点用户必须注意舍入错误。例如,1.0/3*3 == 1在几乎所有现代编程语言中的计算结果为false。对于非专业人士来说更令人惊讶,1.0/10*10 == 1也是如此。

但是,有些浮点系统至少似乎能够更好地处理这些问题。特别是,我在Apple II和Commodore Vic-20的模拟器中尝试了上述两种测试,并且在每种情况下每个表达式都评估为真。这是违反直觉的:非常原始的系统似乎比更先进的系统更好。

旧的浮点系统如何在上述测试中得到理想的答案?假设现代的IEEE浮点数有充分的理由做其他事情,那么它在交换中获得了什么?或换句话说,导致旧浮点系统被抛弃的问题是什么,即使它们能够代表1/10和1/3而没有最麻烦的舍入误差?

编辑:Simon Byrne正确地指出了我在上面列出的确切测试,确实传递了IEEE浮点数。我不知道我用这些错误做了什么,无法重现它。但是,这是一个失败的,刚刚在Python中尝试过:

>>> 0.1+0.1+0.1 == 0.3
False

那个确切的测试在Apple II上取得了成功,所以旧系统是如何得到这个结果的,以及权衡的是什么?

2 个答案:

答案 0 :(得分:2)

在数学上,不可能找到一个能够准确表示所有分数的数字系统的基数,因为有无数的素数。如果要精确存储分数,则必须单独存储分子和分母,这会使计算更复杂。

如果将分数存储为单个值,则某些操作会引入小错误。如果重复执行,错误将会累积并且可能会变得明显。

解决此问题的方法有两种:

  • 如果您可以找到公分母,请按比例缩放所有值并使用整数。例如,使用整数美分而不是浮点美元。

  • 在适当的时候对数字进行舍入。很多时候,只要打印一个或两个数字小于最大精度的浮点数就足够了。

测试浮点数的相等性不能像整数那样进行。这有点像计算两组人并测试这些组的大小是否相同,并测试两个瓶子中是否有相同数量的牛奶。
对于“牛奶”测试,您必须说明数量可能会有多大差异仍然被视为“相等”。

Apple II没有浮点硬件,它的BASIC允许浮点计算。我猜他们包含了相同测试的错误,或者他们使用了10个基数(BCD,见harold的评论)。

答案 1 :(得分:1)

我的猜测是他们可能只是因为你碰巧选择的特定例子而幸运。例如,该语句在IEEE754 binary32算法中是正确的:

>>> import numpy as np
>>> np.float32(0.1) + np.float32(0.1) + np.float32(0.1) == np.float32(0.3)
True

基于this posting,Apple II没有提供硬件浮点,因此确切的细节取决于软件提供的任何内容(听起来好像不同的软件提供了不同的实现)。如果他们碰巧使用相同的24位有效数字(或另一个给出类似结果),那么你会看到相同的答案。

更新:this document似乎表明Applesoft Basic确实使用了24位有效数字(不是25 - 24加上隐含的1 - 正如之前的链接似乎暗示的那样),这可以解释为什么你看到了相同的结果为binary32算法。