Python 小数位数与浮点数和小数有关。十进制

Python 小数位数与浮点数和小数有关。十进制,python,floating-point,decimal,floating-accuracy,Python,Floating Point,Decimal,Floating Accuracy,我似乎对浮标失去了很多精度 例如,我需要解一个矩阵: 4.0x -2.0y 1.0z =11.0 1.0x +5.0y -3.0z =-6.0 2.0x +2.0y +5.0z =7.0 这是我用于从文本文件导入矩阵的代码: f = open('gauss.dat') lines = f.readlines() f.close() j=0 for line in lines: bits = string.split(line, ',') s=[] for i in

我似乎对浮标失去了很多精度

例如,我需要解一个矩阵:

4.0x -2.0y 1.0z =11.0
1.0x +5.0y -3.0z =-6.0
2.0x +2.0y +5.0z =7.0
这是我用于从文本文件导入矩阵的代码:

f = open('gauss.dat')
lines =  f.readlines()
f.close()

j=0
for line in lines:
    bits = string.split(line, ',')
    s=[]
    for i in range(len(bits)):
        if (i!= len(bits)-1):
            s.append(float(bits[i]))
            #print s[i]
    b.append(s)
    y.append(float(bits[len(bits)-1]))
我需要使用gauss seidel进行求解,所以我需要重新排列x、y和z的方程:

x=(11+2y-1z)/4
y=(-6-x+3z)/5
z=(7-2x-2y)/7
这是我用来重新排列方程式的代码
b
是系数矩阵,
y
是答案向量:

def equations(b,y):
    i=0
    eqn=[]
    row=[]
    while(i<len(b)):
        j=0
        row=[]
        while(j<len(b)):
            if(i==j):
                row.append(y[i]/b[i][i])
            else:
                row.append(-b[i][j]/b[i][i])
            j=j+1
        eqn.append(row)
        i=i+1
    return eqn
我得到的是:

y=-1.2-0.20000000000000001x+0.59999999999999998z
这似乎不是一个大问题,但当您将数字提高到非常高的倍数时,错误相当大。有办法解决这个问题吗?我尝试了
Decimal
类,但它不能很好地与powers(即
Decimal(x)**2)配合使用


有什么想法吗?

我对Decimal类不太熟悉,无法帮助您解决问题,但您的问题是,十进制分数通常无法用二进制表示,因此您看到的是最接近的近似值;如果不使用特殊类(比如Decimal),就无法避免这个问题

EDIT:
decimal类对您来说工作不正常怎么办?只要我从一个字符串开始,而不是一个浮点数,幂就可以正常工作

>>> import decimal
>>> print(decimal.Decimal("1.2") ** 2)
1.44

说明了十进制的必要性和用法。十进制非常清楚,如果还没有,您应该检查一下。

IEEE浮点是二进制的,而不是十进制的。不存在精确为0.1或其任意倍数的固定长度二进制分数。它是一个重复的分数,就像十进制的1/3

请阅读

除Decimal类之外的其他选项包括

  • 使用公共Lisp或其他具有精确有理数的语言

  • 使用,例如,将双对数转换为闭合有理数


首先,您的输入可以简化很多。您不需要读取和解析文件。您可以用Python符号声明您的对象。评估文件

b = [
    [4.0, -2.0,  1.0],
    [1.0, +5.0, -3.0],
    [2.0, +2.0, +5.0],
]
y = [ 11.0, -6.0, 7.0 ]
其次,y=-1.2-0.200000000001X+0.5999999998Z并不罕见。0.2或0.6的二进制表示法没有精确的表示形式。因此,显示的值是原始非精确表示的十进制近似值。几乎所有类型的浮点处理器都是如此

您可以尝试Python2.6模块。有一个旧的软件包可能会有所帮助

是的,将浮点数提高到幂会增加错误。因此,您必须确保避免使用浮点数的最右边位置,因为这些位主要是噪声

显示浮点数时,必须对其进行适当的四舍五入,以避免看到噪声位

>>> a
0.20000000000000001
>>> "%.4f" % (a,)
'0.2000'

再看看,这里有一些答案。我给出的一个实际使用python作为示例语言…

对于这样的任务,我建议不要使用十进制模块。它的目的实际上更多地是以有限的精度处理现实世界的十进制数(例如,匹配人类簿记实践),而不是执行精确的数学运算。有些数字不能像二进制数字那样精确地用十进制表示,用十进制数字进行算术运算也比其他数字慢得多

相反,如果你想要精确的结果,你应该使用有理算术。它们将数字表示为分子/指示子对,因此可以准确地表示所有有理数。如果你只使用乘法和除法(而不是像平方根这样的运算,这会导致无理数),你永远不会失去精度

正如其他人所提到的,Python2.6将有一个内置的rational类型,不过请注意,这并不是一个真正的高性能实现——为了速度,您最好使用类似的库。只需将对float()的调用替换为gmpy.mpq(),您的代码现在应该会给出精确的结果(尽管出于显示目的,您可能希望将结果格式化为float)

下面是一个稍微整理过的代码版本,用于加载将使用gmpy有理数的矩阵:

def read_matrix(f):
    b,y = [], []
    for line in f:
        bits = line.split(",")
        b.append( map(gmpy.mpq, bits[:-1]) )
        y.append(gmpy.mpq(bits[-1]))
    return b,y

这不是对你问题的回答,而是相关的:

#!/usr/bin/env python
from numpy import abs, dot, loadtxt, max
from numpy.linalg import solve

data = loadtxt('gauss.dat', delimiter=',')
a, b = data[:,:-1], data[:,-1:]
x = solve(a, b) # here you may use any method you like instead of `solve`
print(x)
print(max(abs((dot(a, x) - b) / b))) # check solution
例如:

$ cat gauss.dat
4.0, 2.0, 1.0, 11.0
1.0, 5.0, 3.0, 6.0 
2.0, 2.0, 5.0, 7.0

$ python loadtxt_example.py
[[ 2.4]
 [ 0.6]
 [ 0.2]]
0.0

@道格:我添加了对Python2.6及其分数模块的引用。无需更改语言-只需使用一个rational算术库,如“其任意倍数”是什么意思?有一个固定长度的二进制分数正好是0.5。是的,但没有一个固定长度的二进制分数正好是0.1(十分之一),或0.1的任意倍数。@Doug Currie 0.5是0.1的倍数,所以最后一部分不是真的;)我需要从文件输入,因为我的程序必须具有足够的通用性来处理NxN矩阵。%.4f不是字符串格式吗?Python符号描述任何大小的矩阵似乎都不是很清晰。为什么要编写自己的解析器?为什么要查找“,”和转换浮动?只需对矩阵使用Python表示法。所有数字都转换为字符串进行打印。您的源代码是十进制的。("0.2"). Python以二进制近似方式工作。当您请求输出时——任何输出——都会转换回字符串。总是。要求字符串中有意义的数字,而不是所有的数字。我之前遇到的幂的问题是我试图将其提高到0.5的幂。为此,我不得不写decimal.decimal(“1.2)**decimal.decimal(“0.5”)您缺少一个引号。也许这就是问题所在。如果您觉得它太冗长,您可以始终使用D=decimal.decimal;D(“1.2”)**D(“0.5”)
$ cat gauss.dat
4.0, 2.0, 1.0, 11.0
1.0, 5.0, 3.0, 6.0 
2.0, 2.0, 5.0, 7.0

$ python loadtxt_example.py
[[ 2.4]
 [ 0.6]
 [ 0.2]]
0.0