经常使用的几个点
1.可以传递给Decimal整型或者字符串参数,但不能是浮点数据,因为浮点数据本身就不准确。需要先将浮点数转化为字符串
传入浮点数 5.55 和 传入字符串 ‘5.55’
from decimal import *
print(Decimal(5.55)*100)
print(Decimal('5.55')*100)
print(Decimal('4.20') + Decimal('2.10'))
x = 4.20
y = 3.10
print(Decimal(str(x)) + Decimal(str(y)))
#运行结果分别是:
#554.9999999999999822364316060
#555.00
#6.30
#7.3
2.要从浮点数据转换为Decimal类型
from decimal import *
print(Decimal.from_float(22.222))
#运行结果:22.22200000000000130739863379858434200286865234375
3.通过设定有效数字,限定结果样式:
from decimal import *
getcontext().prec = 5
print(Decimal(1)/Decimal(7))
print(Decimal(1.00)/Decimal(3.0))
#运行结果,五个有效数字:0.14286
#运行结果:0.33333
当然精度提升的同时,肯定带来的是性能的损失。在对数据要求特别精确的场合(例如财务结算),这些性能的损失是值得的。但是如果是大规模的科学计算,就需要考虑运行效率了。毕竟原生的float比Decimal对象肯定是要快很多的。
4.四舍五入,保留几位小数
from decimal import *
print(Decimal('50.5679').quantize(Decimal('0.00')))
#运行结果四舍五入保留了两位小数:50.57
5.Decimal 结果转化为string
from decimal import *
print(str(Decimal('3.40').quantize(Decimal('0.0'))))
#运行结果:3.4
因为文章是转发过来的,我执行的结果并不是str,还待研究
特别注意:prec为有效数字长度。
如果prec的长度比数字的长度小的话,*100得出的数就不对了
from decimal import *
print(getcontext()) # Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])
num,num1 = '12355','123.55'
getcontext().prec = len(num) +2
print(Decimal(num1)*100 == Decimal(num)) #True
getcontext().prec = 3
# todo 如果prec的长度比数字的长度小的话,*100得出的数就不对了
print(Decimal(num1)*100) #1.24E+4
print(Decimal(num1)) #123.55
print(Decimal(num1)*100 == Decimal(num)) #False
print(Decimal(num)) #12355
6.python decimal.quantize()参数rounding的各参数解释与行为
我最开始其实是由于疑惑ROUND_FLOOR和 ROUND_DOWN的表现区别才看了一波文档,但是感觉拉出一票以前没有留意过的东西。
贴一个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)
直接阅读上面的解释十分抽象,下面我结合例子来解释一下在正负数不同的情况下 他们究竟有着什么样的行为
1)首先给出一组负数的后一位超过5的数据:
from decimal import *
x = Decimal('-3.333333333') + Decimal('-2.222222222')
print(x) # -5.555555555
print(x.quantize(Decimal('1.0000'), ROUND_HALF_EVEN)) # -5.5556
print(x.quantize(Decimal('1.0000'), ROUND_HALF_DOWN)) # -5.5556
print(x.quantize(Decimal('1.0000'), ROUND_CEILING)) # -5.5555
print(x.quantize(Decimal('1.0000'), ROUND_FLOOR)) # -5.5556
print(x.quantize(Decimal('1.0000'), ROUND_UP)) # -5.5556
print(x.quantize(Decimal('1.0000'), ROUND_DOWN)) # -5.5555
ROUND_HALF_EVEN 和 ROUND_HALF_DOWN:EVEN是quansize的默认设置值,可以通过getcontext()得到,EVEN四舍五入进了一位,DOWN为接近最近的0进了一位。
ROUND_CEILING 和 ROUND_FLOOR:CEILING超过5没有进位是因为它倾向正无穷,FLOOR为了总是变得更小所以进了一位。
ROUND_UP 和 ROUND_DOWN:UP始终进位,DOWN始终不会进位。
2)再多对比一组后一位没有超过5的数据:
from decimal import *
x = Decimal('-3.333333333') + Decimal('-1.111111111')
print(x) # -4.444444444
print(x.quantize(Decimal('1.0000'), ROUND_HALF_EVEN)) # -4.4444
print(x.quantize(Decimal('1.0000'), ROUND_HALF_DOWN)) # -4.4444
print(x.quantize(Decimal('1.0000'), ROUND_CEILING)) # -4.4444
print(x.quantize(Decimal('1.0000'), ROUND_FLOOR)) # -4.4445
print(x.quantize(Decimal('1.0000'), ROUND_UP)) # -4.4445
print(x.quantize(Decimal('1.0000'), ROUND_DOWN)) # -4.4444
ROUND_HALF_EVEN 和 ROUND_HALF_DOWN:EVEN是quansize的默认设置值,可以通过getcontext()得到,EVEN由于达不到四舍五入所以不进位,DOWN同样也不进位。
ROUND_CEILING 和 ROUND_FLOOR:CEILING倾向正无穷不进位,FLOOR即使没有超过5,但是为了总是变得更小进了一位。
ROUND_UP 和 ROUND_DOWN:UP始终进位,DOWN始终不会进位。
3)正数部分后面数大于5的情况:
from decimal import *
x = Decimal('3.333333333') + Decimal('2.222222222')
print(x) # 5.555555555
print(x.quantize(Decimal('1.0000'), ROUND_HALF_EVEN)) # 5.5556
print(x.quantize(Decimal('1.0000'), ROUND_HALF_DOWN)) # 5.5556
print(x.quantize(Decimal('1.0000'), ROUND_CEILING)) # 5.5556
print(x.quantize(Decimal('1.0000'), ROUND_FLOOR)) # 5.5555
print(x.quantize(Decimal('1.0000'), ROUND_UP)) # 5.5556
print(x.quantize(Decimal('1.0000'), ROUND_DOWN)) # 5.5555
ROUND_HALF_EVEN 和 ROUND_HALF_DOWN:EVEN是quansize的默认设置值,可以通过getcontext()得到,EVEN由于达到四舍五入所以进位,DOWN同样进位。
ROUND_CEILING 和 ROUND_FLOOR:CEILING正数始终进位,FLOOR在正数则始终不会进位。
ROUND_UP 和 ROUND_DOWN:UP始终进位,DOWN始终不会进位。
4)正数部分后面数小于5的情况:
from decimal import *
x = Decimal('3.333333333') + Decimal('1.111111111')
print(x) # 4.444444444
print(x.quantize(Decimal('1.0000'), ROUND_HALF_EVEN)) # 4.4444
print(x.quantize(Decimal('1.0000'), ROUND_HALF_DOWN)) # 4.4444
print(x.quantize(Decimal('1.0000'), ROUND_CEILING)) # 4.4445
print(x.quantize(Decimal('1.0000'), ROUND_FLOOR)) # 4.4444
print(x.quantize(Decimal('1.0000'), ROUND_UP)) # 4.4445
print(x.quantize(Decimal('1.0000'), ROUND_DOWN)) # 4.4444
ROUND_HALF_EVEN 和 ROUND_HALF_DOWN:EVEN是quansize的默认设置值,可以通过getcontext()得到,EVEN由于没有达到四舍五入所以不进位,DOWN同样不进位。
ROUND_CEILING 和 ROUND_FLOOR:CEILING正数始终进位,FLOOR在正数则始终不会进位。
ROUND_UP 和 ROUND_DOWN:UP始终进位,DOWN始终不会进位。
总结:
其实这里我们通过上面一组例子可以发现,正数的行为非常可预期也非常简单,负数的情况稍复杂,有些函数就是设计为负数在某些情况中使用的。正数中无法重现的ROUND_DOWN和ROUND_FLOOR的区别,ROUND_DOWN是无论后面是否大于5都不会管保持原状,而Floor在正数中的行为也是如此,但是在负数中为了倾向无穷小,所以无论是否大于5,他都会变得更小而进位。反而ROUND_UP和ROUND_DOWN的行为是最可预期的,那就是无论后面数大小,UP就进位,DOWN就始终不进位。
参考:https://blog.csdn.net/weixin_37989267/article/details/79473706