使用SymPy在Python中解指数函数

1 投票
1 回答
53 浏览
提问于 2025-04-12 22:03

我有一个小的网页应用,它可以输入三个点,然后计算出一个抛物线函数或者一个指数函数。下面是抛物线的代码:

@app.route("/calculate/parabola", methods=["POST"])
def calculate_parabola():
    content = request.get_json()
    p1_X = content["p1_X"]
    p1_Y = content["p1_Y"]
    p2_X = content["p2_X"]
    p2_Y = content["p2_Y"]
    p3_X = content["p3_X"]
    p3_Y = content["p3_Y"]
    
    a, b, c = symbols("a,b,c")
    eq1 = Eq((a*(p1_X**2)+b*p1_X+c),p1_Y)
    eq2 = Eq((a*(p2_X**2)+b*p2_X+c), p2_Y)
    eq3 = Eq((a*(p3_X**2)+b*p3_X+c), p3_Y)

    eq_result = solve((eq1, eq2, eq3), (a,b,c))
    print(eq_result)

    returnJSON = {
        "function": f"{eq_result[a]}*x^2+{eq_result[b]}*x+{eq_result[c]}",
        "success": 1
    }
    return returnJSON

这个代码运行得很好。但是问题来了

@app.route("/calculate/exponential-function", methods=["POST"])
def calculate_exponential_function():
    print("calculating...")
    content = request.get_json()
    p1_X = content["p1_X"]
    p1_Y = content["p1_Y"]
    p2_X = content["p2_X"]
    p2_Y = content["p2_Y"]
    p3_X = content["p3_X"]
    p3_Y = content["p3_Y"]
    
    a, b, c = symbols("a,b,c", real=True)
    # eq1 = Eq((a*(b**p1_X)+c), p1_Y)
    # eq2 = Eq((a*(b**p2_X)+c), p2_Y)
    # eq3 = Eq((a*(b**p3_X)+c), p3_Y)

    eq1 = Eq((a*(b**p1_X)+c), p1_Y)
    eq2 = Eq((a*(b**p2_X)+c), p2_Y)
    eq3 = Eq((a*(b**p3_X)+c), p3_Y)


    # eq_result = solve((eq1, eq2, eq3), (a,b,c))
    eq_result = solve((eq1, eq2, eq3), (a,b,c))

    print(eq_result)

    returnJSON = {}

    if(eq_result == []):
        returnJSON = {
        "success": 0
        }
    else:
        returnJSON = {
        "function": f"{eq_result[a]}*({eq_result[b]}**x)+{eq_result[c]}",
        #"function": f"{eq_result[a]}*x+{eq_result[c]}",
        "success": 1
        }

    return returnJSON

如果一切正常,"eq_result" 应该是这样的: {a: 5/6, b: -1/6, c: 1} 但是当我执行 calculate_exponential_function() 时,"eq_result" 输出的却是(例如): [(-27/5, -2/3, 32/5), (1, 2, 0)] 我是不是哪里做错了?如果需要更多信息,请告诉我。

1 个回答

1

solve()这个函数的返回值有点奇怪,但对于这种奇怪的情况来说,它还是比较友好的(如果说有什么不好的话,就是返回不同、不兼容的对象而不是None,这在Python中是不太常见的,令人惊讶,不过它大多数情况下返回的是一个结果的list)。

根据文档 https://docs.sympy.org/latest/explanation/solve_output.html

solve()函数的输出可能看起来很复杂,因为它可能会随机返回六种不同类型的输出(除了抛出错误)。造成这种情况的原因是历史原因,更倾向于人类交互而不是程序使用。输出的类型将取决于方程的类型(以及输入方式)和提供的符号数量(以及提供方式)。

你可以通过设置dict=True来让它的表现更好(不过输出仍然是一个包含零个或一个条目的列表,或者可能有多个条目,但我不确定在这种情况下是否可能)。

>>> x, y = symbols("x y")
>>> solve(x + y, {x, y})
[{x: -y}]
>>> solve([x + y], {x, y})  # ???
{x: -y}
>>> solve([x + y], {x, y}, dict=True)  # always list of dict(s)
[{x: -y}]

来自 solve()

如果你传入了需要求解的符号,输出会根据你传入的符号数量、是否传入了表达式列表以及是否解决了线性系统而有所不同。通过使用dict=Trueset=True可以获得统一的输出。

更让人困惑的是,solve()dict=True(或set=True)的情况下不会返回那些本身就是值的结果,因为它们不“有趣”,所以在我简单实验中,如果你想要完整的结果集合,它们需要放入结果字典中。

>>> x, y = symbols("x y")
>>> solve(x + y, {x, y}, dict=True)  # doesn't bother with y=y or y=-x
[{x: -y}]
>>> solve(x + y, {y}, dict=True)     # force solving for y
[{y: -x}]

全部在一起!

def calculate_exponential_function():
    content = request.get_json()
    p1_X = content["p1_X"]
    p1_Y = content["p1_Y"]
    p2_X = content["p2_X"]
    p2_Y = content["p2_Y"]
    p3_X = content["p3_X"]
    p3_Y = content["p3_Y"]
    
    a, b, c = symbols("a b c", real=True)

    eq1 = Eq((a*(b**p1_X)+c), p1_Y)
    eq2 = Eq((a*(b**p2_X)+c), p2_Y)
    eq3 = Eq((a*(b**p3_X)+c), p3_Y)

    eq_result = solve((eq1, eq2, eq3), {a,b,c}, dict=True)

    if not eq_result:  # no solution: empty list
        return {
            "success": 0,
        }

    eq_result = eq_result[0]  # TODO consider case of multiple results

    # add missing keys (alt: dict of values and .update())
    for key in (a, b, c):
        if key not in eq_result:
            eq_result[key] = key

    return {
        "function": f"{eq_result[a]}*({eq_result[b]}**x)+{eq_result[c]}",
        "success": 1,
    }

撰写回答