我有一个很长的表达,我认为可以简化,我认为sympy
将是完美的方式。不幸的是,公式依赖于几个整数除法,我找不到任何方法来表示sympy
中的那些。
>>> x=Symbol('x')
>>> (x+1)/2
x/2 + 1/2
显然不是我想要的,1/2
不是整数。
>>> (x+1)//2
TypeError: unsupported operand type(s) for //: 'Add' and 'int'
显然sympy
无法处理//
。
>>> Integer((x+1)/2)
# A long list of error messages, ending with ...
TypeError: Integer can only work with integer expressions.
似乎Integer
仅用于处理常数,而不是公式。
有一个函数trunc
,但它似乎没有做我想要的任何事情。
有没有办法在sympy
中表示整数除法?
答案 0 :(得分:5)
我假设你想要一个通过以下测试的函数div
:
from sympy import sympify, simplify, Symbol
def test_div(div):
# check that div behaves as intended for integers
for i in range(-5,5):
for j in range(-5,5):
if j==0: continue
assert i//j == div(sympify(i),sympify(j))
# check that div’s output can be simplified
x = Symbol("x", integer=True)
assert simplify( div(x+1,2) - div(x-1,2) ) == 1
您可以使用模运算符实现整数除法,如下所示:
div = lambda x,y: (x-x%y)/y
由于SymPy支持模数算术并且能够简化它,因此该函数通过了上述测试。但是,如果不能进行完全简化,您最终会得到可能不合需要的模数表达式。
正如评论中已经提到的,SymPy提供了一个floor
函数,它可以用来获取整数除法(这也是表达式的//
运算符的实现方式):
div = lambda x,y: sympy.floor(x/y)
但是,floor
不支持简化,因此无法进行第二次测试。
答案 1 :(得分:1)
创建分段函数可能是最佳选择。它将响应简化请求,并将根据参数的模数相对于您要除的整数来保留各种解决方案。在一个表达式中使用piecewise_flatten
可能需要将所有内容折叠在一起。
def idiv(n, d):
from sympy.core.compatibility import as_int
d = as_int(d); assert d > 0
args = []
for i in range(d):
N = n - i
args.append((N/d, Eq(Mod(N, d), i)))
args[-1] = (args[-1][0], True)
return Piecewise(*args)
例如,
>>> print(factor_terms(idiv(x+1,3)))
Piecewise(
((x + 1)/3, Eq(Mod(x + 1, 3), 0)),
(x/3, Eq(Mod(x, 3), 1)),
((x - 1)/3, True))