测试由于浮点数限制而导致的舍入错误

时间:2018-08-14 11:25:54

标签: python python-2.7 floating-point binary rounding

我最近了解到浮点数的主要限制之一:一些数字不能用二进制正确地表示,因此可能给出的答案不够精确。

在知道round(2.675, 2)round(2.665, 2)都等于2.67的情况下,我尝试编写一些代码,以给出具有此属性的数字列表(四舍五入不正确)。

请在下面或此重新修改中查看我的代码: https://repl.it/@FTBlover123/Float-Rounding-Test

Test = True
number1 = 0.005
number2 = 0.015
count = 0
count_per_test = 5
while Test:
    if round(number1, 2) == round(number2, 2):
        print number1, number2, round(number1, 2), round(number2, 2)
        count += 1
    else:
        pass
    number1 += 0.005
    number2 += 0.005
    if count == count_per_test:
        answer = raw_input("End Program? Y / N: ")
        if answer == "Y":
            print "Program Ended"
            Test = False
        elif answer == "N":
            print "Searching For %s more rounding errors" % (count_per_test)
            count = 0
        else:
            print "Error, raw_input incorrect"
            Test = False

#2.675 is a known number with a rounding error.
print 2.665, 2.675, round(2.675, 2), round(2.665, 2)
#79.705 should have one according to the results, but it doesn't truly.
print 79.695, 79.705, round(79.695, 2), round(79.705, 2)

最后2个print是一个例子。

尽管由于float的限制,代码确实似乎返回了一些舍入错误,但这些似乎是非真实值(第一个除外)。 这是因为我使用的是float 0.005(不能用二进制表示),它本身会导致新的number1number2成为其本已不正确的self的不正确版本!通过将number1number2递增0.001(也不能用二进制表示)可以很容易地证明这一点,因为这还会导致答案仍然不正确,但也有差异!

因此,我的问题:

是否可以创建代码来正确检查由于浮点数限制而导致的舍入错误,而又不会遭受我们试图测试的确切缺陷的困扰? (尽管对此类示例的库也将表示赞赏,但我对修复代码更感兴趣)

我的错误输出之间的间隔似乎呈指数增长。

  • 0.005 0.015 0.01 0.01
  • 0.035 0.045 0.04 0.04
  • 1.025 1.035 1.03 1.03
  • 21.535 21.545 21.54 21.54

  • 79.695 79.705 79.7 79.7

  • 9164.075 9164.085 9164.08 9164.08

  • 36933.455 36933.465 36933.46 36933.46

是什么原因造成的?对于正确的不正确舍入的浮点数也是如此吗?

2 个答案:

答案 0 :(得分:1)

好吧,正如您所注意到的,您不能只继续添加0.005,因为0.005不能表示为浮点数。

该怎么办?使用可代表的数字!

2675可以精确地表示为浮点数(不超过2 ^ 53的每个整数),也可以等于1000。因此,2675.0/1000.0虽然不能表示为浮点数,但会舍入 到最接近的可表示浮点数,就像文字2.675一样。 (为此,您可以使用267.5/100.0,但我认为最好使用整数。)

因此,与其增加要以这种方式检查的值,不如增加分子并每次进行除法。

答案 1 :(得分:0)

首先,有关python内部浮点算法的更多信息,请阅读this。因为您的示例使用了相同的值(2.675的舍入并得到2.67,但是您希望得到2.68),所以您可能已经阅读了此文档。

现在,我尝试回答您的一些问题:

问:是否可以创建检查...的代码?

A:是的,但是您需要使用除float以外的其他算法。如果您要检查为什么将值四舍五入,可以使用十进制模块查看值的浮点表示。

您写道“根据结果,79.705应该有一个,但这并不是真的。”

那是不正确的:

>>> from decimal import Decimal
>>> t = 79.695
>>> print (Decimal(t))
79.69499999999999317878973670303821563720703125

如您所见,内部浮点数表示形式不同于十进制值,因为如果您在这些值上使用“打印”之类的内容,则python已经舍入。 如果“常规”二进制浮点运算不够好,则该模块也可以用于十进制浮点运算。

问题是,为什么要有这样的数字列表?因为在大多数情况下,表示错误根本没有问题。只有cases个地方需要考虑这个问题。