Django中小数四舍五入不符合预期,如何实现指定结果?
Django 3.2.16 实现传统四舍五入的解决方案
问题原因
Django 3.2的Round函数默认采用银行家舍入法(四舍六入五成双),即当舍去位为5且后续无有效数字时,会将前一位调整为偶数。这与你需要的「逢5进1」传统四舍五入逻辑不一致,导致结果不符合预期。
解决方案
由于Django 3.2未提供修改舍入模式的参数,我们可以通过数学运算手动模拟传统四舍五入逻辑:
跨数据库通用方案
from django.db.models import ExpressionWrapper, F, Cast, Floor from django.db.models.fields import FloatField, IntegerField amount_annotation = ExpressionWrapper( # 逻辑:原始值*100 +0.5 后取整,直接得到目标整数结果 Floor( (F(amount_field) * (Cast(F('income__ownership'), FloatField()) / 10000)) * 100 + 0.5 ), output_field=IntegerField() )
逻辑说明
- 先计算原始乘积:
F(amount_field) * (Cast(F('income__ownership'), FloatField()) / 10000) - 乘以100将两位小数位转至整数部分:比如
37.715 * 100 = 3771.5 - 加0.5实现逢5进1:
3771.5 + 0.5 = 3772.0 - 用
Floor取整得到最终整数结果:3772
数据库特定方案(以PostgreSQL为例)
如果你的项目基于PostgreSQL,可以直接调用数据库原生ROUND函数并指定舍入模式:
from django.db.models import Func, ExpressionWrapper, F, Cast from django.db.models.fields import FloatField, IntegerField class TraditionalRound(Func): function = 'ROUND' template = "%(function)s(%(expressions)s, 2, 'plain')" amount_annotation = ExpressionWrapper( TraditionalRound( F(amount_field) * (Cast(F('income__ownership'), FloatField()) / 10000) ) * 100, output_field=IntegerField() )
内容的提问来源于stack exchange,提问作者user369287
相关产品推荐
相关产品推荐

