Sympy似乎随着数字的增加而崩溃

时间:2016-01-22 01:22:55

标签: python sympy

我一直在玩弄同情,并决定制作一个任意方程解算器,因为我的财务课变得有点沉闷。我写了一个基本框架,并开始玩一些例子,但有些工作,有些不是出于某种原因。

foreach (CustomSearchRowBasic customBasicSearchRow in transSearchRow.customSearchJoin) {
    // ????

    CustomRecordSearchRowBasic itmfulfillmentidRecord = customBasicSearchRow.searchRowBasic as CustomRecordSearchRowBasic;
    foreach(SearchColumnCustomField customField in itmfulfillmentidRecord.customFieldList) {
        if (customField.scriptId == "custrecord_ssccbarcode") {
            SearchColumnStringCustomField stringField = customField as SearchColumnStringCustomField;

            string itmfulfillmentid = stringField.searchValue;
        }
    }
}

这是我到目前为止的代码。我想如果需要的话我可以把它剥离成一个基本的例子,但我也想知道是否有更好的方法来实现这种系统。在我完成此操作之后,我希望能够添加任意方程式并在输入除一个参数之外的所有方法时解决它们。

例如,如果我输入(对于等式0),FV = 1000,PV = 500,i = .02,n为空我得到35.0027887811465这是正确的答案。如果我重做它并将FV更改为4000,它将返回一个空列表作为答案。

另一个例子,当我输入FV,PV和n时,程序似乎挂起了。当我输入小数字时,我得到RootOf()答案而不是简单的小数。

任何人都可以帮助我吗?

旁注:我正在使用SymPy 0.7.6和Python 3.5.1,我很确定它是最新的

2 个答案:

答案 0 :(得分:2)

这是一个浮点精度问题。 solve默认情况下将解决方案插入到原始等式中并对其进行评估(使用浮点算法)以便对错误解决方案进行排序。您可以通过设置check=False来停用此功能。例如,对于Hugh Bothwell的代码

for fv in range(1870, 1875, 1):
    sols = sp.solve(eq.subs({FV:fv}), check=False)
    print("{}: {}".format(fv, sols))

给出了

1870: [66.6116466112007]
1871: [66.6386438584579]
1872: [66.6656266802551]
1873: [66.6925950919998]
1874: [66.7195491090752]

答案 1 :(得分:1)

我没有答案,但我确实有一个更简单的演示案例; - )

import sympy as sp

FV, n = sp.symbols("FV n")
eq = sp.Eq(FV, sp.S("500 * 1.02 ** n"))

# see where it breaks
for fv in range(1870, 1875, 1):
    sols = sp.solve(eq.subs({FV:fv}))
    print("{}: {}".format(fv, sols))

产生

1870: [66.6116466112007]
1871: [66.6386438584579]
1872: []
1873: []
1874: []

guess 这是准确性分解到足以找不到n的可验证解决方案的地方吗?

此外,虽然我正在做一个相当广泛的重写,你可能会觉得有用。它与您的代码几乎完全相同,但是以更加松散耦合的方式。

import sympy as sp

class Equation:
    def __init__(self, label, equality_str, eq="=="):
        self.label = label
        # parse the equality
        lhs, rhs = equality_str.split(eq)
        self.equality = sp.Eq(sp.sympify(lhs), sp.sympify(rhs))
        # index free variables by name
        self.vars = {var.name: var for var in self.equality.free_symbols}

    def prompt_for_values(self):
        # show variables to be entered
        var_names = sorted(self.vars, key=str.lower)
        print("\nFree variables are: " + ", ".join(var_names))
        print("Enter a value for all but one (press Enter to skip):")
        # prompt for values by name
        var_values = {}
        for name in var_names:
            value = input("Value of {}: ".format(name)).strip()
            if value:
                var_values[name] = sp.sympify(value)
        # convert names to Sympy variable references
        return {self.vars[name]:value for name,value in var_values.items()}

    def solve(self):
        values = self.prompt_for_values()
        solutions = sp.solve(self.equality.subs(values))
        # remove complex answers
        solutions = [sol.evalf() for sol in solutions if sol.is_real]
        return solutions

    def __str__(self):
        return str(self.equality)

# Define some equations!
equations = [
    Equation("Time value of money (discrete)",   "FV == PV * (1 + i) ** n"),
    Equation("Time value of money (continuous)", "FV == PV * exp(i * n)"  )
]

# Create menu
menu_lo = 1
menu_hi = len(equations) + 1
menu_prompt = "\n".join(
    [""]
    + ["{}: {}".format(i, eq.label) for i, eq in enumerate(equations, 1)]
    + ["{}: Exit".format(menu_hi)]
    + ["? "]
)

def get_int(prompt, lo=None, hi=None):
    while True:
        try:
            value = int(input(prompt))
            if (lo is None or lo <= value) and (hi is None or value <= hi):
                return value
        except ValueError:
            pass

def main():
    while True:
        choice = get_int(menu_prompt, menu_lo, menu_hi)
        if choice == menu_hi:
            print("Goodbye!")
            break
        else:
            solutions = equations[choice - 1].solve()
            num = len(solutions)
            if num == 0:
                print("No solutions found")
            elif num == 1:
                print("1 solution found: " + str(solutions[0]))
            else:
                print("{} solutions found:".format(num))
                for sol in solutions:
                    print(sol)

if __name__ == "__main__":
    main()