Python浮点数计算⼩数取舍指南
浮点算术:争议和限制
浮点数在计算机硬件中表⽰为以 2 为基数(⼆进制)的⼩数。
举例⽽⾔,⼗进制的⼩数
0.125=1/10 + 2/100 + 5/1000
同理⼆进制⼩数
0.001
0*1/2+0*1/4+1*1/8得⼗进制的0.125(⼆进制的⼩数转换为⼗进制主要是乘以2的负次⽅)
这两个⼩数具有相同的值,唯⼀真正的区别是第⼀个是以 10 为基数的⼩数表⽰法,第⼆个则是 2 为基数。
⼤多数的⼗进制⼩数都不能精确地表⽰为⼆进制⼩数。这导致在⼤多数情况下,你输⼊的⼗进制浮点数都只能近似地以⼆进制浮点数形式储存在计算机中。
⽤⼗进制来理解这个问题显得更加容易⼀些。考虑分数 1/3 。
我们可以得到它在⼗进制下的⼀个近似值 0.3
或者,更近似的,:0.33
或者,更近似的,:0.333
以此类推。结果是⽆论你写下多少的数字,它都永远不会等于 1/3 ,只是更加更加地接近 1/3 。
同样的道理,⽆论你使⽤多少位以 2 为基数的数码,⼗进制的 0.1 都⽆法精确地表⽰为⼀个以 2 为基数的⼩数。 在以 2 为基数的情况下, 1/10 是⼀个⽆限循环⼩数
计算机只认识⼆进制,⼗进制之间的运算,需要将⼗进制转换为⼆进制在进⾏⼆进制之间的运算。
因为 Python 只会打印计算机中存储的⼆进制值的⼗进制近似值
>>>print(0.1+0.1+0.1)
0.30000000000000004
虽然病态的情况确实存在,但对于⼤多数正常的浮点运算使⽤来说,你只需简单地将最终显⽰的结果舍⼊为你期望的⼗进制数值即可得到你期望的结果。  通常已⾜够,对于更精度的控制可参看  中  ⽅法的格式描述符。
对于需要精确⼗进制表⽰的使⽤场景,请尝试使⽤  模块,该模块实现了适合会计应⽤和⾼精度应⽤的⼗进制运算(数学上的四舍五⼊)
#新Decimal的重要性仅由输⼊的位数决定。上下⽂精度和舍⼊仅在算术运算期间发挥作⽤。
>>>print(decimal.Decimal('0.01')+decimal.Decimal('0.01')+decimal.Decimal('0.01'))
0.03
总是输⼊ decimal.Decimal('0.01')过于笨拙。
可将构造器简写为⼀个字母:
>>>D = decimal.Decimal
>>>D('0.01') + D('0.01') + D('0.01')
如何正确进⾏四舍五⼊
来测试⼀下,0.125 ,0.375 分别保留两位⼩数是多少:
print(decimal.Decimal('0.125').quantize(Decimal('.01')))  0.12
print(decimal.Decimal('0.375').quantize(Decimal('.01')))  0.38
浮点数的基数什么意思
来并未达到预期效果,
我们可以通过指定quantize() 中 rounding参数来确定进位⽅式。如果没有指定 rounding参数,那么默认使⽤上下⽂提供的进位⽅式。rounding=ROUND_HALF_EVEN
ROUND_HALF_EVEN实际上就是 奇进偶舍!如果要指定真正的四舍五⼊,那么我们需要在 quantize中指定进位⽅式为
ROUND_HALF_UP:
quantize(Decimal('.01'), rounding=decimal.ROUND_HALF_UP)
Python的官⽅中⽂⽂档
关于使⽤round函数
round(number[, ndigits])
返回 number 舍⼊到⼩数点后 ndigits 位精度的值。 如果 ndigits 被省略或为 None,则返回最接近输⼊值的整数。
对于⽀持  ⽅法的内置类型,结果值会舍⼊⾄最接近的 10 的负 ndigits 次幂的倍数;如果与两个倍数同样接近,则选⽤偶数。因此,round(0.5) 和 round(-0.5) 均得出 0 ⽽ round(1.5) 则为 2。ndigits 可为任意整数值(正数、零或负数)。如果省略了 ndigits 或为 None ,则返回值将为整数。否则返回值与 number 的类型相同。
round对⼩数的精确度采⽤了 四舍六⼊五成双的⽅式。( 奇进偶舍的处理⽅法)
其具体要求举例如下(以保留两位⼩数为例):⼀个⼩数 a.bcd
1. 如果 d⼩于5,直接舍去,则舍去。例如:5.214保留两位⼩数为5.21。
2. 如果 d⼤于5,直接进位。例如5.216保留两位⼩数为5.22。
3. 如果 d等于5:⽽且d后⾯不再有数,要根据应看尾数“5”的前⼀位C决定是舍去还是进⼊: 如果是奇数进⼊,如果是偶数舍去。例如
5.215保留两位⼩数为5.22; 5.225保留两位⼩数为5.22。
4. 如果 d等于5:⽽且d后⾯仍有数。例如
5.2254保留两位⼩数为5.23,也就是说如果5后⾯还有数据,则⽆论奇偶都要进⼊。
四舍五⼊(保留2位⼩数,只舍不⼊)
通过计算的途径,很难将最终结果截取2位,通过字符串,直接截取就可以了。
>>> a = 12.345
>>> str(a).split('.')[0] + '.' + str(a).split('.')[1][:2]
'12.34'
def get_float(f_str,n):
a, b, c = f_str.partition('.')
c = c[:n]
return ".".join([a, c])
if __name__ == '__main__':
print(get_float("12.345", 2))
#使⽤re模块
a = 12.345
re.findall(r"\d{1,}?\.\d{2}", str(a))
四舍五⼊(保留2位⼩数,只⼊不舍)
不根据⼩数位第三位进⾏四舍五⼊,只要后⾯有值就进⾏⼊
print(decimal.Decimal('0.370001').quantize(Decimal('.01'), rounding=decimal.ROUND_UP)) 0.38
根据⼩数位第三位进⾏四舍五⼊
先截取成三位⼩数再进⾏ rounding=decimal.ROUND_UP
向上/下取整(ceil(a)函数与floor(a)函数)
import math
# 向上取整 3
import math
print("il(2.3) => ", il(2.3))
print("il(2.6) => ", il(2.6))
# 向下取整 2
print("math.floor(2.3) => ", math.floor(2.3))
print("math.floor(2.6) => ", math.floor(2.6))

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。