【问题标题】:lambdified sympy expression returns incorrect resultlambdified sympy 表达式返回不正确的结果
【发布时间】:2017-01-23 11:25:16
【问题描述】:

我遇到了以下问题,我先简单解释一下是怎么回事:

f(x)
g(x, y) = f(x) - y

我们期望从那里开始

g(x, f(x)) = f(x) - f(x) = 0

lambdified g(x,y) 返回非常接近零而不是零的值。这是重现问题的代码。只有当我在f(x) 中放入足够数量的log 评估时它才会出现

要点:https://gist.github.com/marekyggdrasil/39a24213ebaba6293464d116821cc334

来源:

from sympy import Symbol, pprint, log, lambdify

# setting symbols
g1 = Symbol("gamma1")
g2 = Symbol("gamma2")
g3 = Symbol("gamma3")
g4 = Symbol("gamma4")
rt = Symbol("rt")

# setting expressions
criteria  = (g1 * log(g1, 2.0))/2.0
criteria += (g2 * log(g2, 2.0))/2.0
criteria += (g3 * log(g3, 2.0))/2.0
criteria += (g4 * log(g4, 2.0))/2.0
rooteq = criteria - rt

print "\ncriteria function: "
pprint(criteria)

print "\ncriteria function - rt: "
pprint(rooteq)

# lambdifying expressions to callable functions
tsymbols = [g1, g2, g3, g4, rt]
lambfun_criteria = lambdify(tsymbols, criteria)
lambfun_rooteq = lambdify(tsymbols, rooteq)

# example point x
x = [0.25006462253641376, 2.2501938662000542, 2.2501938662000542, 2.2501938662000542, 0.0]

# evaluating of criteria on x
rootval = lambfun_criteria(*x)

# setting rt to this evaluation
x[4] = rootval

print "\nactual evaluation of rooteq: " + str(lambfun_rooteq(*x))
print "\nexpected evaluation of rooteq: " + str(- x[4] + lambfun_criteria(*x))

输出

$ python lambdifytest.py 

criteria function: 
0.721347520444482⋅γ₁⋅log(γ₁) + 0.721347520444482⋅γ₂⋅log(γ₂) + 0.721347520444482⋅γ₃⋅log(γ₃) + 0.721347520444482⋅γ₄⋅log(γ₄)

criteria function - rt: 
0.721347520444482⋅γ₁⋅log(γ₁) + 0.721347520444482⋅γ₂⋅log(γ₂) + 0.721347520444482⋅γ₃⋅log(γ₃) + 0.721347520444482⋅γ₄⋅log(γ₄) - rt

actual evaluation of rooteq: 4.4408920985e-16

expected evaluation of rooteq: 0.0

【问题讨论】:

  • 你好,看起来是floating point representation error,基本上,因为你在浮点上执行操作,如果你只执行0.4+0.3+0.2,你会累积不等于0的近似误差,你'将在 python 中得到0.8999999999999999
  • 我不这么认为,反对它的论点是它没有积累,只有一个评估在路上,也许我应该提出一个不同的问题:为什么最后和最后源代码行提供不同的结果?
  • 如您所见,lambfun_rooteq(*x)- x[4] + lambfun_criteria(*x) 在完全相同的值上进行完全相同的计算,但产生不同的结果,我认为这是关键问题。
  • 您期望的方程不适用于浮点运算。结果可能会受到您(或lambdify,无论它是什么)如何排序操作或编译器如何为中间结果分配寄存器的影响。除非在最微不足道的情况下,否则您不能既使用浮点数又期望得到准确的结果。
  • 那么请阅读浮点数,因为这是完全正常的预期行为。

标签: python floating-point sympy numerical-methods lambdify


【解决方案1】:

我发现当SymPy 表达式被lambdified 时可以指定一个自定义数学模块。就我而言,mpmath 提供了帮助。

导入 mpmath 并将精度设置为您认为足够的值

from mpmath import mp
mp.dps = 15

告诉 SymPy 您希望 lambda 函数使用 mpmath 来处理浮点运算

lambfun_criteria = lambdify(tsymbols, criteria, "mpmath")
lambfun_rooteq = lambdify(tsymbols, rooteq, "mpmath")

最后我得到了输出

actual evaluation of rooteq: 0.0
expected evaluation of rooteq: 0.0

问题的原因如下,创建的 lambda 函数中使用的默认浮点运算与比较结果的脚本中使用的不同。

如果有人需要复制粘贴,我用完整的解决方案文件更新了要点

https://gist.github.com/marekyggdrasil/39a24213ebaba6293464d116821cc334#file-lambdify_test_solution-py

编辑:忘记提供文档参考

http://docs.sympy.org/dev/modules/utilities/lambdify.html

【讨论】:

  • 如果你想使用任意精度的算法,你还不如留在 SymPy 中并使用 expr.evalf(precision),它是 mpmath 的包装器(但返回一个 SymPy 表达式)。
猜你喜欢
  • 2017-11-22
  • 2017-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多