2

我有一个处理帐户和 COD 交易的系统。当客户通过 COD 付款时,我需要向上或向下舍入美分。

Eg.
Total = 64.42 - rounds to: 64.40
Total = 64.57 - rounds to 64.60

我试图找出在 python 中执行此操作的最佳方法,并将差异存储在数据库中的十进制字段中。

我正在使用 DJANGO。我试图使用十进制的 ROUND_05UP 部分,但我不知道该怎么做。我写了一个自定义过滤器来显示它,但这甚至不起作用:

@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。

干杯,本

4

3 回答 3

3

如果我理解正确,传入的金额已经是一个精确的整数美分,你只想四舍五入到最接近的 10 美分的倍数,但保留已经结束的值5。那是对的吗?这是一个使用剩余近点方法的简单解决方案。

from decimal import Decimal

def round_to_10_cents(x):
    """
    Round a Decimal value to the nearest multiple of 0.10,
    unless already an exact multiple of 0.05.

    """
    remainder = x.remainder_near(Decimal('0.10'))
    if abs(remainder) == Decimal('0.05'):
        return x
    else:
        return x - remainder


# Test code.
for x in range(80, 120):
    y = Decimal(x) / Decimal('1E2')
    print "{0} rounds to {1}".format(y, round_to_10_cents(y))

样本输出:

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
于 2012-10-28T10:51:33.187 回答
3

您所说的这种四舍五入称为瑞典四舍五入

  • 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.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

@Mark Dickingson 的回答做了不同的事情。它导致较大的累积舍入误差。

于 2015-05-12T06:11:58.793 回答
2

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

于 2015-05-12T10:56:43.730 回答