如何将 evalf() 应用于来自 symengine.py 的表达式?

How to apply evalf() to an expression from symengine.py?

我们在 python 的包 symengine 中找不到任何 evalf()。有没有?

更详细的解释我们的问题。

我们正在尝试切换到 symengine 而不是 sympy,因为我们认为基本加速。我们使用符号代数工具来解决在组合随机结构生成中有应用的优化问题。

在对 sympy 进行一些测试后,我们发现解决一些 "innocent-looking" 优化问题需要在范围 1e+24 及以上进行中间计算(但最终他们最终提供了正确答案)。然后我发现我误用了 sympy 的函数 subs(),因为它不如带有替换字典的 evalf() 精确。

函数 subs 的手册中描述了此问题:

If the substitution will be followed by numerical
evaluation, it is better to pass the substitution to
evalf as

>>> (1/x).evalf(subs={x: 3.0}, n=21)
0.333333333333333333333

rather than

>>> (1/x).subs({x: 3.0}).evalf(21)
0.333333333333333314830

因为前者将确保所需的精度水平 获得。事实上,使用标准 sympy.subs() 函数或 symengine.subs() 替换 e+24 会抛出无穷大,尽管 e+24 仍在 numpy.float64 的范围内,我怀疑它是我的标准类型当我调用内置 float(...) 函数时,机器会转换为。

我们知道 "lambdify",如果您进行重复替换并希望获得较高的数值精度,这是推荐的步骤,但这将是下一步。我们无法使用 python 解释器的手册,因为代码是预编译的,而且在互联网上也很难找到。查看源代码也无济于事(但也许我错过了一些东西)。

symengine 上还没有 evalf。以下是实现上述目标的方法,

In [14]: (1/x).subs({x: 3}).n(73, real=True)
Out[14]: 0.333333333333333333333

请注意,如果您喜欢下面的操作,它将以精度 53(15 位十进制数字)进行替换

In [15]: (1/x).subs({x: 3.0}).n(73, real=True)
Out[15]: 0.333333333333333314830

您可以将 subs 与 Float(3.0, dps=21) 一起使用,而不仅仅是 3.0 来进行更高精度的计算。下面的示例将适用于 symengine 和 sympy。

In [16]: (1/x).subs({x: Float(3.0, dps=21)})
Out[16]: 0.333333333333333333333

请注意,symengine 中的 .n() 更喜欢二进制数字而不是十进制数字的精度,并且 real=True 需要为实数域提供,否则它会假设复杂并给你一个复数虚部 0. 并且会比 real=True.

慢一点