鱼C论坛

 找回密码
 立即注册
查看: 2549|回复: 9

[已解决]python3 浮点数精度问题

[复制链接]
发表于 2017-9-1 14:09:18 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 chunchun2017 于 2017-9-1 14:13 编辑

今天在调试程序的时候发现python3.6.2中,浮点数只精确到小数点后面第16位,当遇到17位小数时,判断将会出错,如下:
>>> 1/3
0.3333333333333333
>>> 0.36363636363636366>0.36363636363636365
False
>>> round(0.36363636363636366,17)>round(0.36363636363636365,17)
False
>>> 0.36363636363636366<0.36363636363636365
False
>>> 0.36363636363636366==0.36363636363636365
True

请教一下,如果因为题目的要求,程序里面要求比较第17位甚至更多位的小数时,怎么办?
最佳答案
2017-9-1 18:17:30
分数表达式不会有精度损失

fractions
  1. >>> from fractions import Fraction
  2. >>> 1/2 + 1/3 == 5/6
  3. False
  4. >>> Fraction(1,2)+Fraction(1,3)==Fraction(5,6)
  5. True
  6. >>> Fraction('1/2')+Fraction('1/3')==Fraction('5/6')
  7. True
  8. >>>
复制代码

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-9-1 14:20:56 | 显示全部楼层
  1. >>> print(1 / 3)
  2. 0.3333333333333333
  3. >>> import decimal #调用decimal模块
  4. >>> print(decimal.Decimal(1) / decimal.Decimal(3))使用Decimal型数据
  5. 0.3333333333333333333333333333 #这时小数点后已经有28位了
  6. >>> decimal.getcontext().prec = 56 #能否进一步增加精度?把设置为56位
  7. >>> print(decimal.Decimal(1) / decimal.Decimal(3))
  8. 0.33333333333333333333333333333333333333333333333333333333
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-9-1 14:26:53 | 显示全部楼层
不用decimal模块的话,只要把原来的数x10,x100,x1000...这样不就可以了?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-9-1 15:01:47 | 显示全部楼层

调用decimal后,printr打印出来确实是更精确了,请问我如果需要比较两个17位小数的大小呢?
比如:if (0.36363636363636366<0.36363636363636365)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-9-1 15:02:13 | 显示全部楼层
jerryxjr1220 发表于 2017-9-1 14:26
不用decimal模块的话,只要把原来的数x10,x100,x1000...这样不就可以了?


这样好像不行,刚试了一下
>>> a=0.36363636363636366*100
>>> b=0.36363636363636365*100
>>> a==b
True
>>> a
36.36363636363637
>>> b
36.36363636363637
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-9-1 15:32:04 | 显示全部楼层
自己写个函数。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-9-1 15:46:17 | 显示全部楼层
chunchun2017 发表于 2017-9-1 15:01
调用decimal后,printr打印出来确实是更精确了,请问我如果需要比较两个17位小数的大小呢?
比如:if (0 ...

这是没有办法用decimal解决的,因为它是首先把一个float数转换为decimal,而float的精度不够,在内部二进制存储和计算时会带来误差,即不是每个浮点数都可以对应一个二进制数。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-9-1 15:51:33 | 显示全部楼层
冬雪雪冬 发表于 2017-9-1 15:46
这是没有办法用decimal解决的,因为它是首先把一个float数转换为decimal,而float的精度不够,在内部二进 ...

又想了一下,可以这样变通,整数是不限定位数的,用整数出发生成你说的数,再比较:
  1. >>> decimal.Decimal(36363636363636366)/decimal.Decimal(100000000000000000)
  2. Decimal('0.36363636363636366')
  3. >>> decimal.Decimal(36363636363636365)/decimal.Decimal(100000000000000000)
  4. Decimal('0.36363636363636365')
  5. >>> decimal.Decimal(36363636363636366)/decimal.Decimal(100000000000000000) > decimal.Decimal(36363636363636365)/decimal.Decimal(100000000000000000)
  6. True
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-9-1 16:44:45 From FishC Mobile | 显示全部楼层
chunchun2017 发表于 2017-9-1 15:02
这样好像不行,刚试了一下
>>> a=0.36363636363636366*100
>>> b=0.36363636363636365*100

你理解错了,我的意思是通过x10的N次方可以把小数点往后移动N位,如果你需要比较小数点后17位就需要x10的17次方,然后直接取整比较就好了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-9-1 18:17:30 | 显示全部楼层    本楼为最佳答案   
分数表达式不会有精度损失

fractions
  1. >>> from fractions import Fraction
  2. >>> 1/2 + 1/3 == 5/6
  3. False
  4. >>> Fraction(1,2)+Fraction(1,3)==Fraction(5,6)
  5. True
  6. >>> Fraction('1/2')+Fraction('1/3')==Fraction('5/6')
  7. True
  8. >>>
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-28 22:26

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表