Python综述

Python综述,python,django,decimal,rounding,Python,Django,Decimal,Rounding,我有一个处理帐户和COD交易的系统。当客户通过COD付款时,我需要对美分进行四舍五入或四舍五入 Eg. Total = 64.42 - rounds to: 64.40 Total = 64.57 - rounds to 64.60 我试图找出在python中实现这一点的最佳方法,并将差异存储在数据库的十进制字段中 我用的是DJANGO。我试着用小数的四舍五入部分,但我不知道怎么做。我编写了一个自定义过滤器来显示它,但这甚至不起作用: @register.filter def currency

我有一个处理帐户和COD交易的系统。当客户通过COD付款时,我需要对美分进行四舍五入或四舍五入

Eg.
Total = 64.42 - rounds to: 64.40
Total = 64.57 - rounds to 64.60
我试图找出在python中实现这一点的最佳方法,并将差异存储在数据库的十进制字段中

我用的是DJANGO。我试着用小数的四舍五入部分,但我不知道怎么做。我编写了一个自定义过滤器来显示它,但这甚至不起作用:

@register.filter
def currency(value, arg='en_US', symbol=True):

    saved = '.'.join([x for x in locale.getlocale() if x]) or (None, None)
    given = arg and ('.' in arg and str(arg) or str(arg) + '.UTF-8')

    # Workaround for Python bug 1699853 and other possibly related bugs.
    if '.' in saved and saved.split('.')[1].lower() in ('utf', 'utf8'):
        saved = saved.split('.')[0] + '.UTF-8'

    if saved == (None, None) and given == '':
        given = 'en_US.UTF-8'

    try:
        locale.setlocale(locale.LC_ALL, given)

        return locale.currency(value or 0, symbol, True)

    except (TypeError, locale.Error):
        return ''

    finally:
        locale.setlocale(locale.LC_ALL, saved)


@register.filter
def currency_cash(value):
    value = decimal.Decimal(value)
    return currency(value.quantize(Decimal(10) ** -2, rounding=decimal.ROUND_05UP))
有人写过这样的函数吗

更新:原因是在澳大利亚,我们没有少于5美分的硬币。因此,45.55将保持为45.55

干杯,
Ben

如果我理解正确,传入金额已经是一个精确的整数分,您只需要四舍五入到最接近的10分倍数,但保留已经以
5
结尾的值。对吗?下面是一个使用该方法的简单解决方案

样本输出:

0.80 rounds to 0.80
0.81 rounds to 0.80
0.82 rounds to 0.80
0.83 rounds to 0.80
0.84 rounds to 0.80
0.85 rounds to 0.85
0.86 rounds to 0.90
0.87 rounds to 0.90
0.88 rounds to 0.90
0.89 rounds to 0.90
0.90 rounds to 0.90
0.91 rounds to 0.90
0.92 rounds to 0.90
0.93 rounds to 0.90
0.94 rounds to 0.90
0.95 rounds to 0.95
0.96 rounds to 1.00
0.97 rounds to 1.00
0.98 rounds to 1.00
0.99 rounds to 1.00
1.00 rounds to 1.00
1.01 rounds to 1.00
1.02 rounds to 1.00
1.03 rounds to 1.00
1.04 rounds to 1.00
1.05 rounds to 1.05
1.06 rounds to 1.10
1.07 rounds to 1.10
1.08 rounds to 1.10
1.09 rounds to 1.10
1.10 rounds to 1.10
1.11 rounds to 1.10
1.12 rounds to 1.10
1.13 rounds to 1.10
1.14 rounds to 1.10
1.15 rounds to 1.15
1.16 rounds to 1.20
1.17 rounds to 1.20
1.18 rounds to 1.20
1.19 rounds to 1.20
0.80 rounds to 0.8
0.81 rounds to 0.8
0.82 rounds to 0.8
0.83 rounds to 0.85
0.84 rounds to 0.85
0.85 rounds to 0.85
0.86 rounds to 0.85
0.87 rounds to 0.85
0.88 rounds to 0.9
0.89 rounds to 0.9
0.90 rounds to 0.9
0.91 rounds to 0.9
0.92 rounds to 0.9
0.93 rounds to 0.95
0.94 rounds to 0.95
0.95 rounds to 0.95
0.96 rounds to 0.95
0.97 rounds to 0.95
0.98 rounds to 1.0
0.99 rounds to 1.0
1.00 rounds to 1.0
1.01 rounds to 1.0
1.02 rounds to 1.0
1.03 rounds to 1.05
1.04 rounds to 1.05
1.05 rounds to 1.05
1.06 rounds to 1.05
1.07 rounds to 1.05
1.08 rounds to 1.1
1.09 rounds to 1.1
1.10 rounds to 1.1
1.11 rounds to 1.1
1.12 rounds to 1.1
1.13 rounds to 1.15
1.14 rounds to 1.15
1.15 rounds to 1.15
1.16 rounds to 1.15
1.17 rounds to 1.15
1.18 rounds to 1.2
1.19 rounds to 1.2

您正在谈论的这种舍入类型称为:

  • 1分四舍五入为0分
  • 2美分四舍五入到0美分
  • 3美分至5美分
  • 4美分至5美分
等等

from decimal import Decimal as D, ROUND_HALF_EVEN  # or ROUND_HALF_UP

def round_to_5_cents(d):
    """
    Round a Decimal value to the nearest multiple of 0.05,
    """
    return (d*2).quantize(D('0.1'), ROUND_HALF_EVEN)/D(2)

for x in range(80, 120):
    d = D(x) * D('0.01')
    print "{0} rounds to {1}".format(d, round_to_5_cents(d))
样本输出:

0.80 rounds to 0.80
0.81 rounds to 0.80
0.82 rounds to 0.80
0.83 rounds to 0.80
0.84 rounds to 0.80
0.85 rounds to 0.85
0.86 rounds to 0.90
0.87 rounds to 0.90
0.88 rounds to 0.90
0.89 rounds to 0.90
0.90 rounds to 0.90
0.91 rounds to 0.90
0.92 rounds to 0.90
0.93 rounds to 0.90
0.94 rounds to 0.90
0.95 rounds to 0.95
0.96 rounds to 1.00
0.97 rounds to 1.00
0.98 rounds to 1.00
0.99 rounds to 1.00
1.00 rounds to 1.00
1.01 rounds to 1.00
1.02 rounds to 1.00
1.03 rounds to 1.00
1.04 rounds to 1.00
1.05 rounds to 1.05
1.06 rounds to 1.10
1.07 rounds to 1.10
1.08 rounds to 1.10
1.09 rounds to 1.10
1.10 rounds to 1.10
1.11 rounds to 1.10
1.12 rounds to 1.10
1.13 rounds to 1.10
1.14 rounds to 1.10
1.15 rounds to 1.15
1.16 rounds to 1.20
1.17 rounds to 1.20
1.18 rounds to 1.20
1.19 rounds to 1.20
0.80 rounds to 0.8
0.81 rounds to 0.8
0.82 rounds to 0.8
0.83 rounds to 0.85
0.84 rounds to 0.85
0.85 rounds to 0.85
0.86 rounds to 0.85
0.87 rounds to 0.85
0.88 rounds to 0.9
0.89 rounds to 0.9
0.90 rounds to 0.9
0.91 rounds to 0.9
0.92 rounds to 0.9
0.93 rounds to 0.95
0.94 rounds to 0.95
0.95 rounds to 0.95
0.96 rounds to 0.95
0.97 rounds to 0.95
0.98 rounds to 1.0
0.99 rounds to 1.0
1.00 rounds to 1.0
1.01 rounds to 1.0
1.02 rounds to 1.0
1.03 rounds to 1.05
1.04 rounds to 1.05
1.05 rounds to 1.05
1.06 rounds to 1.05
1.07 rounds to 1.05
1.08 rounds to 1.1
1.09 rounds to 1.1
1.10 rounds to 1.1
1.11 rounds to 1.1
1.12 rounds to 1.1
1.13 rounds to 1.15
1.14 rounds to 1.15
1.15 rounds to 1.15
1.16 rounds to 1.15
1.17 rounds to 1.15
1.18 rounds to 1.2
1.19 rounds to 1.2

@马克·迪金森的回答做了另一件事。它会导致更大的累积舍入误差。

至于舍入它似乎是为了符合一些旧的规则而添加的,没有或几乎没有实际应用(特别是,它是维基百科文章中唯一缺少的python舍入方法)。

因此45.55保留为45.55,但45.56轮升到45.60,45.54轮降到45.50。是吗?你最初的问题不清楚是否需要保留0.05倍@马克·迪金森的答案更好,所以我把它投了更高的票,并删除了我的。