Python中分数与浮点数计算精度丢失问题的技术求助
解决SymPy与Fractions库混合计算时的浮点数精度丢失问题
你的推测完全正确——问题出在浮点数的二进制表示局限性:像10/3这类分数无法用二进制浮点数精确表示,存储的是近似值,后续替换到表达式中再经SymPy解析时,这些近似误差会被放大,导致结果出现8.0000000000000003、-0.9999999999999999这类不精确值。
核心解决方案:用精确分数类型替代浮点数
直接在矩阵中使用精确分数(而非浮点数),确保所有数值都是精确表示的,从根源避免精度丢失。有两种可行方式:
方式1:使用fractions.Fraction定义矩阵元素
把矩阵中所有分数形式的浮点数替换为Fraction(分子, 分母),这样存储的是精确分数对象,转成字符串时会输出"10/3"而非浮点数近似值。
修改后的矩阵定义:
new_matrix_aux = [['X', 'B', 'X1', 'X2', 'X3', 'X4', 'X5', 'U1', 'U2'], ['X2', Fraction(10,3), 0, 1, Fraction(2,3), Fraction(1,3), Fraction(-2,3), Fraction(-1,3), Fraction(2,3)], ['X1', Fraction(4,3), 1, 0, Fraction(2,3), Fraction(-2,3), Fraction(1,3), Fraction(2,3), Fraction(-1,3)]]
方式2:使用SymPy内置的sp.Rational
SymPy本身提供了精确分数类型Rational,和SymPy的表达式解析更适配,用法和Fraction类似:
new_matrix_aux = [['X', 'B', 'X1', 'X2', 'X3', 'X4', 'X5', 'U1', 'U2'], ['X2', sp.Rational(10,3), 0, 1, sp.Rational(2,3), sp.Rational(1,3), sp.Rational(-2,3), sp.Rational(-1,3), sp.Rational(2,3)], ['X1', sp.Rational(4,3), 1, 0, sp.Rational(2,3), sp.Rational(-2,3), sp.Rational(1,3), sp.Rational(2,3), sp.Rational(-1,3)]]
修改后完整代码示例
import sympy as sp from fractions import Fraction new_matrix_aux = [['X', 'B', 'X1', 'X2', 'X3', 'X4', 'X5', 'U1', 'U2'], ['X2', Fraction(10,3), 0, 1, Fraction(2,3), Fraction(1,3), Fraction(-2,3), Fraction(-1,3), Fraction(2,3)], ['X1', Fraction(4,3), 1, 0, Fraction(2,3), Fraction(-2,3), Fraction(1,3), Fraction(2,3), Fraction(-1,3)]] z_function = "Z = 1 * X1 + 2 * X2 + 3 * X3 + 0 * X4 + 0 * X5 + M * U1 + M * U2" lista_de_operaciones_zj = [] for j in range(1, len(new_matrix_aux[0])): z = z_function for i in range(1, len(new_matrix_aux)): z = z.replace(new_matrix_aux[i][0], str(new_matrix_aux[i][j])) for k in range(1, len(new_matrix_aux[0])): z = z.replace(new_matrix_aux[0][k], '0') z = z.replace(z[0], z[0] + '_' + new_matrix_aux[0][j]) lista_de_operaciones_zj.append(z) print(f'"{z}"') variables, resultados = [], [] for operacion in lista_de_operaciones_zj: variable = operacion.split("Z_")[1].split(" = ")[0] variables.append(variable) expression = operacion.split("= ")[1] resultado = sp.sympify(expression) resultados.append(resultado) output = [variables, resultados] print(output)
运行结果
执行后会得到你期望的精确输出:
[['B', 'X1', 'X2', 'X3', 'X4', 'X5', 'U1', 'U2'], [8, 1, 2, 2, 0, -1, 0, 1]]
内容的提问来源于stack exchange,提问作者Elektvocal95
相关产品推荐
相关产品推荐

