我正在对一个sympy分段函数进行lambd化,试图做这样的事情:
f = Piecewise((1,(p > -1e-10) & (p < 1e-10)), (1/p, True))
g = lambdify(p,f,"numpy")
而
>>> f.subs(p,0)
1
我明白了
>>> g(0)
/usr/lib/python2.7/dist-packages/numpy/__init__.py:1: RuntimeWarning: divide by zero encountered in true_divide
"""
array(1.0)
似乎(lambdified?)-Piecewise在返回具有真实条件的表达式之前先评估所有表达式。有办法解决吗?
答案 0 :(得分:3)
NumPy code printer used by lambdify将Piecewise
转换为
numpy.select(conditions, expressions, default=numpy.nan)
这意味着数组expressions
是在numpy.select
选择该数组的一个元素之前进行完整计算的。解决它的一些方法是:
1)将后端更改为math
(或mpmath
或numpy
以外的任何其他字符),这将导致Piecewise
为翻译为nested if statement。
g = lambdify(p, f, "math")
g(0) # 1, no warnings
2)根据最大/最小/绝对/符号来重写公式,该表达式可以表达一些分段函数并易于进行lambdify。并非总是可能的,但就您而言,
f = 0.5 * (sign(p + 1e-10) + sign(p - 1e-10)) / Max(1e-10, Abs(p)) + 0.5 * (sign(p + 1e-10) - sign(p - 1e-10))
完成任务。诀窍是0.5 * (sign(p + 1e-10) + sign(p - 1e-10))
在p不太接近0时为sign(p),而在p不太接近0时为0。类似地,如果p不太接近0,则0.5 * (sign(p + 1e-10) - sign(p - 1e-10))
为1,当p为0时为{0}。这些因素导致公式从一种模式切换到另一种模式,分母中的Max
在任何情况下都避免了零误差除法。