Python问题与舍入

时间:2015-11-21 15:55:45

标签: python floating-point rounding

我在Python 2.7中有一个舍入问题导致意外输出。我试图让p1和p2的组合总计达到0.6或更少。

lazy val root = (project in file(".")).
  settings(
    name := "TestkitAfterall",
    version := "1.0",
    scalaVersion := "2.11.7"
  )

lazy val akkaVersion = "2.4.0"

libraryDependencies ++=  Seq(
  "com.typesafe.akka" %% "akka-actor" % akkaVersion,
  "com.typesafe.akka" %% "akka-testkit" % akkaVersion,
  "org.scalatest" % "scalatest_2.11" % "2.2.5"
)

然而,当我运行它时,它不包括p11 + p22 = 0.6的所有值:

from itertools import product
P = []
p1 = [0.0,0.2,0.4,0.6]
p2 = [0.0,0.2,0.4,0.6] 
for p11,p22 in product(p1,p2):
    if p11+p22 <= max(p1):    
        P.append((p11,p22))

设置[(0.0, 0.0), (0.0, 0.2), (0.0, 0.4), (0.0, 0.6), (0.2, 0.0), (0.2, 0.2), (0.4, 0.0), (0.6, 0.0)] 时,它可以正常工作。对于不同的p11+p22 <= max(p1)+0.01p1,问题可能会也可能不会发生。我发现这种行为非常奇怪,导致非常不可靠的结果。

这可能与浮动精度问题有关。在我看来,这种行为不应该存在于Python中,因为R和Matlab也没有这种行为。这有什么简单的方法吗?

4 个答案:

答案 0 :(得分:5)

发生了什么事?

计算机具有数字的内部表示。在大多数情况下,这些表示具有固定的位数。这导致仅可表示固定数量的数字。例如,您可能知道像C这样的语言具有整数的最大值。

类似地,您不能存储某些浮点数的精确表示。由于计算机使用基数为2,因此基数10中有一些数字具有短的有限表示但二进制数字很长。有关详细信息,请参阅IEEE 754

如何修复&#34;?

这里没有什么可以解决的,因为一切都像指定的那样工作。但你必须知道这些类型的问题。当你意识到存在问题的事实时,有两种策略可以解决它。

使用 epsilons ( - &gt;不要与确切数字进行比较,但要检查数字是否在数字周围的非常小的间隔内。此间隔的长度通常称为&#34; epsilon&#34;)或使用任意精确表示(见fractions。第二种只有当你可以影响数字如何被放入程序时才有效,例如

from itertools import product
from fractions import Fraction
P = []
p1 = [Fraction(0.0), Fraction(2, 10), Fraction(4, 10), Fraction(6, 10)]
p2 = [Fraction(0.0), Fraction(2, 10), Fraction(4, 10), Fraction(6, 10)]
for p11, p22 in product(p1, p2):
    if p11+p22 <= max(p1):
        P.append((p11, p22))

另见

答案 1 :(得分:1)

因为固定位宽浮点上的limitations,您需要使用任意精度浮点包或明确地与+/- epsilon量进行比较。

Python包含decimal(对于'算法,其工作方式与人们在学校学习的算法相同'):

from itertools import product
import decimal

P = []
p1 = map(decimal.Decimal, ['0.0','0.2','0.4','0.6'])
p2 = map(decimal.Decimal, ['0.0','0.2','0.4','0.6'])
for p11,p22 in product(p1,p2):
    if p11+p22 <= max(p1):    
        P.append((p11,p22))

答案 2 :(得分:1)

如果您想与matlab或R进行比较,或者遇到性能问题,这里有一个简单的方法,np.isclose()作为解决方法。

p1 = [0.0,0.2,0.4,0.6]
p2 = [0.0,0.2,0.4,0.6] 
sums=np.add.outer(p1,p2)
P1,P2=np.meshgrid(p1,p2)
compare = (sums<0.6) | np.isclose(sums,0.6)
print(np.dstack((P1,P2))[compare])

给出:

[[ 0.   0. ]
 [ 0.2  0. ]
 [ 0.4  0. ]
 [ 0.6  0. ]
 [ 0.   0.2]
 [ 0.2  0.2]
 [ 0.4  0.2]
 [ 0.   0.4]
 [ 0.2  0.4]
 [ 0.   0.6]]

答案 3 :(得分:-1)

一种方法是定义一个不同的不等式比较函数,

for p11,p22 in product(p1,p2):
    if less_or_nearly_equal(p11+p22,max(p1)):    
        P.append((p11,p22))

并在比较中使用\而不是&lt; =

{{1}}

(我希望我的语法在函数定义中是正确的。)