Python Decimal.quantize方法疑问:负数ROUND_UP舍入行为异常
问题:Decimal ROUND_UP 舍入异常分析
我用以下代码将浮点数截断到12位小数:
Decimal(val).quantize(Decimal(1).scaleb(-12), rounding=ROUND_UP)
测试时发现一个异常用例,除t4外其余输出均符合预期:
测试代码
from decimal import Decimal, ROUND_UP t1 = Decimal(-0.04).quantize(Decimal(1).scaleb(-2), rounding=ROUND_UP) print(f"t1: {t1}") t2 = Decimal(-0.05).quantize(Decimal(1).scaleb(-2), rounding=ROUND_UP) print(f"t2: {t2}") t3 = Decimal(-0.22).quantize(Decimal(1).scaleb(-2), rounding=ROUND_UP) print(f"t3: {t3}") t4 = Decimal(-0.092314564913).quantize(Decimal(1).scaleb(-12), rounding=ROUND_UP) print(f"t4: {t4}") t5 = Decimal(-0.092314564914).quantize(Decimal(1).scaleb(-12), rounding=ROUND_UP) print(f"t5: {t5}") t6 = Decimal("-0.09231456491391342377614447500").quantize(Decimal(1).scaleb(-12), rounding=ROUND_UP) print(f"t6: {t6}")
输出结果
t1: -0.05 t2: -0.06 t3: -0.23 t4: -0.092314564913 t5: -0.092314564915 t6: -0.092314564914
原因分析
核心问题在于二进制浮点数的精度限制:
- 像
-0.092314564913这类十进制小数无法用二进制浮点数精确存储,实际内存中的值会略大于字面量(更接近0),比如实际为-0.09231456491299999xxxx。 - 当把这个浮点数转换为
Decimal时,得到的数值小数点后12位恰好是-0.092314564913,没有超出12位的剩余部分,因此quantize配合ROUND_UP无需进行舍入,直接保留原12位小数。 t5中的-0.092314564914作为浮点数,实际存储值会略小于字面量(更负),转换为Decimal后小数点后12位之后还有超出部分,ROUND_UP会向远离0的方向舍入到-0.092314564915。t6用字符串直接初始化Decimal,保证了数值的精确性,小数点后12位之后的913...触发ROUND_UP,最终舍入到-0.092314564914。
解决方案
如果需要精确处理十进制小数,建议使用字符串而非浮点数初始化Decimal,从根源避免二进制浮点数的精度误差影响结果。
内容的提问来源于stack exchange,提问作者ssj_100
相关产品推荐
相关产品推荐

