找到最近的好号码

时间:2014-05-22 17:05:48

标签: algorithm formatting currency rounding

给定基础货币GBP £,以及商店接受的其他货币表:

Currency       Symbol     Subunits      LastToGBPRate
------------------------------------------------------
US Dollars     $          100           0.592662000
Euros          €          100           0.810237000
Japanese Yen   ¥          1             0.005834610
Bitcoin        ฿          100000000     301.200000000

我们有一种工作方法可将GBP Pence (AKA cents)中的给定金额转换为Currency X cents。鉴于999(9.99英镑)的价格,对于上述货币,它将返回:

Currency       Symbol
---------------------
US Dollars     1686
Euros          1233
Japanese Yen   1755
Bitcoin        3482570  

这一切都很好。然后我们有一个Format Currency方法,将它们全部转换为漂亮的数字:

Currency       Formatted
---------------------
US Dollars     $16.86
Euros          €12.33
Japanese Yen   ¥1755
Bitcoin        ฿0.03482570  

现在我们要解决的问题是,在给定上述信息的情况下,在通用算法中将这些金额舍入到最接近的meaningful pretty number

这有两个重要的好处:

  • 对于短期中期内的访问者,大多数货币的价格应该是静态的
  • 介绍具有文化意义的价格点的访客,鼓励销售

meaningful number是显示的最小单位不小于£0.10的值,pretty number是以49或{{1}结尾的单位}。示例输出:

99

我知道可以用一个算法来完成所有这些信息,但是我很难解决从哪里开始的问题。谁能告诉我如何实现这一目标,还是指点一下?

请注意,为每种货币存储一般格式规则是不够的,因为假设比特币10x的价格,格式规则将需要更新。我正在寻找一种不需要任何手动维护/检查的解决方案。

4 个答案:

答案 0 :(得分:4)

对于给定的十进制值X,您希望找到最小的整数Y,使得YA + B尽可能接近X,对于某些给定的A和B.在美元的情况下,你有A = .5和B = .49。

一般来说,对于您的问题,A和B可以通过以下公式计算:

V = value of £0.10 in target currency
K = smallest power of ten (10^k) such that 9*10^k >= V
    and k <= -2 (this condition I added based on your examples, but contrary
                 to your definition)
  = 10^min(-2, ceil(log10(V / 9))) 
A = 50 * K
B = 49 * K

请注意,如果没有额外条件,因为0.09美元小于0.10磅,我们将得到14.9,结果为16.86美元。

通过一些转变我们得到了

Y ~ (X - B) / A

由于Y是整数,我们有

Y = round((X - B) / A) 

结果是YA + B.

答案 1 :(得分:1)

  • £0.10转换为当前货币以确定最小可显示数字(SDD)
    (以该货币的可用数字数量为限)。

  • 现在我们基本上有3种数字选择:

    • ... (3rdSDD-1) 9 9(如果3rdSDD为0,则显然会从4thSDD开始,依此类推,因为减法通常有效)

      我们会在10*2ndSDD + 1stSDD < 24

    • 时选择此选项
    • ... 3rdSDD 4 9

      我们会在24 <= 10*2ndSDD + 1stSDD < 74

    • 时选择此选项
    • ... 3rdSDD 9 9

      我们会在74 < 10*2ndSDD + 1stSDD

    • 时选择此选项
  • 从这里弄清楚它应该是微不足道的 一些乘法和模数可以得到2ndSDD1stSDD 基本的减法可以让你... (3rdSDD-1) 一些if语句可以选择上述案例之一。

示例:

对于$16.86,我们的3个选项为$15.99$16.49$16.99
我们从$16.99开始选择74 < 86

对于€12.33,我们的3个选项为€11.99€12.49€12.99
我们从€12.49开始选择24 <= 33 < 74

对于¥1755,我们的3个选项为¥1699¥1749¥1799
我们从¥1749开始选择24 <= 55 < 74

对于฿0.03482570,我们的3个选项为฿0.0299฿0.0349฿0.0399
我们从฿0.0349开始选择24 <= 48 < 74

而且,只是为了显示进位:

对于$100000.23,我们的3个选项为$99999.99$100000.49$100000.99
我们从$99999.99开始选择23 < 24

答案 2 :(得分:1)

这是一个难看的答案:

def retail_round(number):
        """takes a decimal.Decimal and retail rounds it"""
        ending_digits = str(number)[-2:]
        if not ending_digits in ("49","99"):
            rounding_adjust = (99 - int(ending_digits)) % 50
            if rounding_adjust <= 25:
                number = str(number)[:-2]+str(int(ending_digits)+int(rounding_adjust))
            else:
                if str(number)[-3] == '.':
                    number = str(int(number) - .01)
                else:
                    number = str(int(str(number)[:-2]+"00")-1)
        return decimal.Decimal(number)

>>> import decimal
>>> retail_round(decimal.Decimal("15.50"))
Decimal('14.99')
>>> retail_round(decimal.Decimal("15.51"))
Decimal('14.99')
>>> retail_round(decimal.Decimal("15.75"))
Decimal('15.99')
>>> retail_round(decimal.Decimal("1575"))
Decimal('1599')
>>> retail_round(decimal.Decimal("1550"))
Decimal('1499')

编辑:这是一个更好的解决方案,使用decimal.Decimal

Currency = collections.namedtuple("Currency",["name","symbol",
                      "subunits"])

def retail_round(currency, amount):
    """returns a decimal.Decimal amount of the currency, rounded to
49 or 99."""
    adjusted = ( amount / currency.subunits ) % 100 # last two digits
    print(adjusted)
    if adjusted < 24:
        amount -= (adjusted + 1) * currency.subunits # down to 99
    elif 24 <= adjusted < 74:
        amount -= (adjusted - 49) * currency.subunits # to 49
    else:
        amount -= (adjusted - 99) * currency.subunits # up to 99
    return amount

答案 3 :(得分:-1)

  1. 计算价格的最大长度,假设其类似于0.00001。 (你可以通过将0.10英镑兑换成货币,然后取10个基本日志,得到它的ceil和10的幂来做到这一点。
  2. 例如:£0.10 = 17.1421309¥

    log(17.1421309) = 1.234
    ceil(1.234) = 2
    10^2 = 100
    so
    ¥174055 will be ¥174900
    

    调整数字的数字,加1,舍入为50,减去1:

    174055 - &gt; (round((174055/100 + 1)/ 50)* 50-1)* 100 = 174900

    简单明了。