今天抠一抠细节,记录一下Python在乘除法中的精度问题
1.除法计算
1.1 一般情况下的除法
dived = 20
div = 7
r = dived / div
print(r)
# 运算结果
# result = 2.857142857142857
1.2 获取小数点后100位的精度除法(仅支持整数运算)
根据上图发现,一般情况下计算整数除法,结果本应该是一个无限循环小数,但在小数点第16位时系统默认采用了四舍五入的方式保留了结果,从某种意义上讲,这是一种节约系统资源的做法,但如果想要继续计算解决一些高精度的问题时,需要继续向下做运算,那该如何做呢?
答案思路比较简单,分两步走,先通过整除获得整数,然后通过求余和循环的结合获取小数,之后将两者结合即可。
## 除法精度问题(仅支持整数)
## 思路:分部计算,先计算整数部分,后计算小数部分
dived = 20
div = 7
r = ''
if dived > div:
t = dived // div;
r = str(int(t))+'.'
dived = dived % div
else:
r = '0.'
for i in range(100):
dived = dived * 10
t = dived // div
r = r + str(int(t))
dived = dived % div
print(r)
# result
# result = 2.8571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571
通过科学计算器检验结果验证无误。
1.3 获取小数点后100位的精度除法(支持整数&浮点数)
若要解决浮点数的除法精度问题,思路也不难想,只需要将除数和被除数均化为整数即可,这里的思路是先判断两者右移小数点至整数所需要的最大值(10的multiple次方),之后两数分别乘以此最大值(10的multiple次方)再进行整数运算。
dived = 202 ## 定义被除数
div = 71 ## 定义除数
print("被除数是:", dived)
print("除数是:", div, "\n")
r = ''
## 若存在浮点型,则先转化为整数
if type(dived) == float or type(div) == float:
print("存在浮点数")
len_dd = len(str(dived).split(".")[1])
len_d = len(str(div).split(".")[1])
print("dived的小数位:", len_dd)
print("div的小数位:", len_d)
if len_dd > len_d:
multiple = len_dd
else:
multiple = len_d
dived = int(10 ** multiple * dived)
div = int(10 ** multiple * div)
print("dived化为整数:", dived)
print("div化为整数:", div)
else:
print("不存在浮点数")
print("\n正片开始")
## 正片开始
if dived > div:
t = dived // div;
r = str(int(t))+'.'
dived = dived % div
else:
r = '0.'
for i in range(100):
dived = dived * 10
t = dived // div
r = r + str(int(t))
dived = dived % div
print(r)
通过比较两次计算结果和科学计算器结果验证无误。
2.乘法计算
2.1 一般情况下的乘法
一般情况下,两个整数相乘精度没有问题,小数相乘存在精度问题,需要分部解决。
m1 = 0.080189
m2 = 0.0088035
r1 = m1 * m2
print("r1:", r1)
m3 = 0.080189
m4 = 0.00088035
r2 = m3 * m4
print("r2:", r2)
m5 = 801890000000
m6 = 880350000000
r3 = m5 * m6
print("r3:", r3)
2.1 一般情况下的乘法
2.2 解决乘法精度问题
def multiple(m1, m2):
r = ''
## 若存在浮点型,则先转化为整数
if type(m1) == float or type(m2) == float:
print("存在浮点数")
len_m1 = len(str(m1).split(".")[1])
len_m2 = len(str(m2).split(".")[1])
print("m1的小数位:", len_m1)
print("m2的小数位:", len_m2)
m1 = int(10 ** len_m1 * m1)
m2 = int(10 ** len_m2 * m2)
print("m1化为整数:", m1)
print("m2化为整数:", m2)
r = str(m1 * m2)
print("r:", r)
l = len_m1 + len_m2
print("l的总长度:", l)
if l < len(r):
r_front = r[:-l]
r_last = r[-l:]
print(r_front, "-", r_last)
r = r_front + "." + r_last
else:
r = "0." + (l - len(r)) * "0" + r
else:
print("不存在浮点数")
r = m1 * m2
print("结果为:", r)
m1 = 1.111
m2 = 1.1
r1 = m1 * m2
print("r1:", r1) # 正常计算
multiple(m1, m2) # 解决精度问题后的计算
查看结果,r1为一般情况下的计算结果(r1: 1.2221000000000002),解决精度问题后的结果(1.2221)
尝试一下其他几种情况
m1 | m2 | 一般情况下的结果r | 解决精度问题后的结果,multiple(m1,m2) |
---|---|---|---|
1.111 | 1.1 | 1.2221000000000002 | 1.2221 |
0.080189 | 0.00088035 | 7.059438614999999e-05 | 0.00007059438615 |
80189 | 88035 | 7059438615 | 7059438615 |