博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【Python】浮点数计算时的不准确性以及如何进行精确计算
阅读量:4101 次
发布时间:2019-05-25

本文共 5734 字,大约阅读时间需要 19 分钟。

浮点数一个普遍的问题就是在计算机的世界中,浮点数并不能准确地表示十进制。并且,即便是最简单的数学运算,也会带来不可控制的后果。因为,在计算机的世界中只认识0与1

因为在计算机里面,小数是不精确的,例如1.115在计算机中实际上是1.1149999999999999911182,所以当你对这个小数精确到小数点后两位的时候,实际上小数点后第三位是4,所以四舍五入,因此结果为1.11。
这种说法,对了一半。因为并不是所有的小数在计算机中都是不精确的。例如0.125这个小数在计算机中就是精确的,它就是0.125,没有省略后面的值,没有近似,它确确实实就是0.125。
但是如果我们在Python中把0.125精确到小数点后两位,那么它的就会变成0.12,为什么在这里四舍了?
还有更奇怪的,另一个在计算机里面能够精确表示的小数0.375,我们来看看精确到小数点后两位是多少:,为什么这里又五入了?因为在Python 3里面,round对小数的精确度采用了四舍六入五成双的方式。
如果你写过大学物理的实验报告,那么你应该会记得老师讲过,直接使用四舍五入,最后的结果可能会偏高。所以需要使用奇进偶舍的处理方法。
例如对于一个小数a.bcd,需要精确到小数点后两位,那么就要看小数点后第三位:   如果d小于5,直接舍去;如果d大于5,直接进位;
如果d等于5:d后面没有数据,且c为偶数,那么不进位,保留c。d后面没有数据,且c为奇数,那么进位,c变成(c + 1)
python中的decimal模块可以解决上面的烦恼 
decimal模块中,可以通过整数,字符串或原则构建decimal.Decimal对象。如果是浮点数,特别注意因为浮点数本身存在误差,需要先将浮点数转化为字符串。
当然精度提升的同时,肯定带来的是性能的损失。在对数据要求特别精确的场合(例如财务结算),这些性能的损失是值得的。
但是如果是大规模的科学计算,就需要考虑运行效率了。毕竟原生的float比Decimal对象肯定是要快很多的。

Python提供了decimal模块用于十进制数学计算,它具有以下特点:

1.提供十进制数据类型,并且存储为十进制数序列;
2.有界精度:用于存储数字的位数是固定的,可以通过decimal.getcontext().prec=x 来设定,不同的数字可以有不同的精度
3.浮点:十进制小数点的位置不固定(但位数是固定的)

python decimal.quantize()参数rounding的decimal文档里面的解释:

ROUND_CEILING (towards Infinity),
ROUND_DOWN (towards zero),
ROUND_FLOOR (towards -Infinity),
ROUND_HALF_DOWN (to nearest with ties going towards zero),
ROUND_HALF_EVEN (to nearest with ties going to nearest even integer),
ROUND_HALF_UP (to nearest with ties going away from zero), or
ROUND_UP (away from zero).
ROUND_05UP (away from zero if last digit after rounding towards zero would have been 0 or 5; otherwise towards zero)

下面通过具体代码理解每个参数

# -*- coding: utf-8 -*-'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''#作者:cacho_37967865#博客:https://blog.csdn.net/sinat_37967865#文件:dealFloat.py#日期:2019-08-01#备注:python使用浮点类型float计算后,数值可能不对,这时候需要使用decimal模块'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''from decimal import Decimal,getcontextfrom decimal import ROUND_UP,ROUND_DOWN,ROUND_HALF_UP,ROUND_HALF_DOWN,ROUND_HALF_EVEN,ROUND_05UP,ROUND_CEILING ,ROUND_FLOORx = 4.20y = 2.10a = 1.20b = 2.30d = 195.00def float_info():    # a.bcd ,精确2位小数点    i = 1.115  # 在计算机中实际上是1.1149999999999999911182      四舍五入:1.11    j = 0.125  # d后面没有数据,且c为偶数,那么不进位,保留c        四舍五入:0.12    l = 0.1251 # d后面有数据,c变成(c + 1)                       四舍五入:0.13    k = 0.375  # d后面没有数据,且c为奇数,那么进位,c变成(c + 1)   四舍五入:0.38    print('四舍五入:',round(i,2))    print('四舍五入:',round(j, 2))    print('四舍五入:',round(l, 2))    print('四舍五入:',round(k, 2))def decimal_info():    # a.bcd ,精确2位小数点 默认进位方式    i = 1.115  # 在计算机中实际上是1.1149999999999999911182      四舍五入:1.11    j = 0.125  # d后面没有数据,且c为偶数,那么不进位,保留c        四舍五入:0.12    l = 0.1251 # d后面有数据,c变成(c + 1)                       四舍五入:0.13    k = 0.375  # d后面没有数据,且c为奇数,那么进位,c变成(c + 1)   四舍五入:0.38    print('浮点型数据不精确:',Decimal(i))    print('浮点型数据也可能精确:', Decimal(j))    print('传入的是字符串默认方式四舍五入:', Decimal(str(i)).quantize(Decimal('0.00')))   # 1.12    print('传入的是浮点型默认方式四舍五入:',Decimal(i).quantize(Decimal('0.00')))         # 1.11    print('传入的是浮点型默认方式四舍五入:',Decimal(j).quantize(Decimal('0.00')))    print('传入的是浮点型默认方式四舍五入:',Decimal(l).quantize(Decimal('0.00')))    print('传入的是浮点型默认方式四舍五入:',Decimal(k).quantize(Decimal('0.00')))    # 最好传入字符串    print('传入的是字符串真实四舍五入:', Decimal(str(i)).quantize(Decimal('0.00'), ROUND_HALF_UP))    print('传入的是字符串真实四舍五入:', Decimal(str(j)).quantize(Decimal('0.00'), ROUND_HALF_UP))    print('传入的是字符串真实四舍五入:', Decimal(str(l)).quantize(Decimal('0.00'), ROUND_HALF_UP))    print('传入的是字符串真实四舍五入:', Decimal(str(k)).quantize(Decimal('0.00'),ROUND_HALF_UP))    print('传入的是字符串向上取值:', Decimal('0.121').quantize(Decimal('0.00'), ROUND_UP))              # 向上入 0.13    print('传入的是字符串向下取值:', Decimal('0.129').quantize(Decimal('0.00'), ROUND_DOWN))            # 向下舍 0.12    print('传入的是字符串向上四舍五入:', Decimal('0.125').quantize(Decimal('0.00'), ROUND_HALF_UP))      # 最后一位5向上入 0.13    print('传入的是字符串向下四舍五入:', Decimal('0.125').quantize(Decimal('0.00'), ROUND_HALF_DOWN))    # 最后一位5向下舍 0.12    print('传入的是字符串默认方式四舍五入:', Decimal('0.125').quantize(Decimal('0.00'), ROUND_HALF_EVEN))  # 默认四舍五入方式 0.12     quansize的默认设置值    print('传入的是字符串默认方式四舍五入:', Decimal('0.375').quantize(Decimal('0.00'), ROUND_HALF_EVEN))    # 默认四舍五入方式 0.38    print('传入的是字符串精确位数字为5入:', Decimal('5.351').quantize(Decimal('0.00'), ROUND_05UP))       # 精确的最后一位为0或者5向上入,否者向下舍5.36    print('传入的是字符串精确位数字为0入:', Decimal('5.301').quantize(Decimal('0.00'), ROUND_05UP))       # 精确的最后一位为0或者5向上入,否者向下舍5.31    print('传入的是字符串精确位数字非0和5舍:', Decimal('5.399').quantize(Decimal('0.00'), ROUND_05UP))       # 精确的最后一位为0或者5向上入,否者向下舍5.39    print('传入的是字符串正数时与ROUND_UP一致:', Decimal('5.391').quantize(Decimal('0.00'), ROUND_CEILING))     # 5.40    print('传入的是字符串正数时与ROUND_DOWN一致:', Decimal('5.399').quantize(Decimal('0.00'), ROUND_FLOOR))     # 5.39    print('传入的是字符串负数时与ROUND_DOWN一致:', Decimal('-5.399').quantize(Decimal('0.00'), ROUND_CEILING))    # -5.39  趋近于正无穷    print('传入的是字符串负数时与ROUND_UP一致:', Decimal('-5.399').quantize(Decimal('0.00'), ROUND_FLOOR))       # -5.40  趋近于负无穷    print('传入的是字符串与正负无关,最后一位始终进:', Decimal('-5.399').quantize(Decimal('0.00'), ROUND_UP))def float_deal():    z = x + y                # 6.300000000000001    print(z)    if z == 6.30:        print("z计算正确")    else:        print("z计算错误")    c = a + b    print(c)    if c == 3.5:        print("c计算正确")    else:        print("c计算错误")    e = round(195.00 / 24,2)    print(e)    if e == 8.13:        print("e四舍五入正确")    else:        print("e四舍五入错误")def decimal_deal():    getcontext().prec = 3                     # 设置精确值,只针对计算时无法除净时    z = Decimal(str(x)) + Decimal(str(y))    print(type(z),z)    e = Decimal('195.00') / Decimal('24')    print(e)if __name__ == '__main__':    float_info()    decimal_info()    #float_deal()    #decimal_deal()

 

你可能感兴趣的文章
PHP 7 的五大新特性
查看>>
php实现socket(转)
查看>>
PHP底层的运行机制与原理
查看>>
深入了解php底层机制
查看>>
PHP中的stdClass 【转】
查看>>
XHProf-php轻量级的性能分析工具
查看>>
PHP7新特性 What will be in PHP 7/PHPNG
查看>>
比较strtr, str_replace和preg_replace三个函数的效率
查看>>
ubuntu 下编译PHP5.5.7问题:configure: error: freetype.h not found.
查看>>
PHP编译configure时常见错误 debian centos
查看>>
configure: error: Please reinstall the BZip2 distribution
查看>>
OpenCV gpu模块样例注释:video_reader.cpp
查看>>
【增强学习在无人驾驶中的应用】
查看>>
《python+opencv实践》四、图像特征提取与描述——29理解图像特征
查看>>
《python+opencv实践》四、图像特征提取与描述——31 Shi-Tomasi 角点检测& 适合于跟踪的图像特征
查看>>
OpenCV meanshift目标跟踪总结
查看>>
人工神经网络——神经元模型介绍
查看>>
人工神经网络——感知器介绍
查看>>
人工神经网络——反向传播算法(BackPropagation)
查看>>
Windows 窗口底层原理
查看>>