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