2014-05-22 9 views
5

eine Basiswährung der GBP £, und eine Tabelle von anderen Währungen in einem Geschäft akzeptiert Gegeben:Finden Sie die nächste schöne Zahl

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

Wir haben eine Arbeitsmethode, die eine bestimmte Menge in GBP Pence (AKA cents) in Currency X cents umwandelt. Bei einem Preis von 999 (£ 9,99), für die oben genannten Währungen würde es zurück:

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

Das ist alles funktioniert absolut in Ordnung. Wir haben dann eine Format Currency Methode, die sie alle in gut aussehenden Zahlen konvertiert:

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

nun das Problem, das wir lösen wollen, ist diese auf die nächsten meaningful pretty number in einem Allzweck-Algorithmus, um die obigen Informationen runden.

Dies dient zwei wichtige Vorteile:

  • Preise für die meisten Währungen sollten für Besucher über kurz- bis mittelfristigen Zeitrahmen
  • präsentiert sich dem Besucher mit einem kulturell meaningul Preispunkt statisch erscheinen, die
Umsatz ermutigt

Eine meaningful number ist eine, bei der die kleinste angezeigte Einheit nicht kleiner als der Wert von etwa 0,10 £ ist und eine pretty number eine ist, die in 49 oderendet. Beispiel Ausgänge:

Currency  Formatted   Meaninful and Pretty 
----------------------------------------------------- 
US Dollars  $16.86   $16.99 
Euros   €12.33   €12.49 
Japanese Yen ¥1755    ¥1749 
Bitcoin  ฿0.03482570  ฿0.0349 

Ich weiß es möglich ist, diese mit einem einzigen Algorithmus zu tun, mit allen Informationen gegeben, aber ich bin zu kämpfen, selbst zu arbeiten, wo ich anfangen soll. Kann mir jemand zeigen, wie man das erreicht, oder gibt es Hinweise?

Bitte beachten Sie, dass das Speichern einer allgemeinen Formatierungsregel für jede Währung nicht angemessen ist, da zum Beispiel der Preis von Bitcoin 10x angenommen wird, die Formatierungsregel muss aktualisiert werden. Ich suche nach einer Lösung, die keine manuelle Wartung/Überprüfung benötigt.

+0

Ich glaube, Ihre Definition falsch ist, da .01 Dollar weniger als 0,10 Pfund –

+0

(oder sogar 0,09 Dollar) –

Antwort

4

Für einen gegebenen Dezimalwert X wollen Sie die kleinste ganze Zahl Y finden, so dass YA + B so nah wie möglich an X ist, für einige gegebene A und B. Z.B. im Fall von Dollar haben Sie A = .5 und B = .49.

Im Allgemeinen für Ihr Problem, A und B können über die Formel berechnet werden:

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 

Beachten Sie, dass ohne die zusätzliche Bedingung, da 0,09 Dollar weniger als 0,10 Pfund, würden wir 14,9 als das bekommen Ergebnis für 16,86 Dollar.

Mit etwas Transformation erhalten wir

Y ~ (X - B)/A 

Und da Y ganze Zahl ist, haben wir

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

Das Ergebnis ist dann YA + B.

1
  • Convert £0.10 auf die aktuelle Währung die kleinste darstellbare Zahl (SDD)
    (begrenzt durch die Anzahl der zur Verfügung stehenden Ziffern in dieser Währung) zu bestimmen.

  • Jetzt haben wir im Grunde drei Möglichkeiten der Zahlen:

    • ... (3rdSDD-1) 9 9 (wenn 3rdSDD 0 ist, wird es offensichtlich von 4thSDD tragen und so weiter, wie Subtraktion funktioniert in der Regel)

      Wir werden holen Sie dies, wenn 10*2ndSDD + 1stSDD < 24

    • ... 3rdSDD 4 9

      Wir werden diese holen, wenn 24 <= 10*2ndSDD + 1stSDD < 74

    • ... 3rdSDD 9 9

      Wir dies als 74 < 10*2ndSDD + 1stSDD

  • holen werde sollte es trivial sein es von hier aus zu verstehen.
    Einige Multiplikation und Modul, um Sie 2ndSDD und 1stSDD zu erhalten.
    Grundsubtraktion, um Sie zu bekommen..
    Einige if-Anweisungen, um einen der obigen Fälle auszuwählen.

Beispiel:

Für $16.86, unsere 3-Entscheidungen sind $15.99, $16.49 und $16.99.
Wir wählen $16.99 seit 74 < 86.

Für €12.33 sind unsere 3 Auswahlmöglichkeiten €11.99, €12.49 und €12.99.
Wir wählen €12.49 seit 24 <= 33 < 74.

Für ¥1755 sind unsere 3 Auswahlmöglichkeiten ¥1699, ¥1749 und ¥1799.
Wir wählen ¥1749 seit 24 <= 55 < 74.

Für ฿0.03482570, unsere 3-Entscheidungen sind ฿0.0299, ฿0.0349 und ฿0.0399.
Wir wählen ฿0.0349 seit .

Und gerade den Übertrag zeigen:

Für $100000.23, unsere 3 Möglichkeiten $99999.99, $100000.49 und $100000.99 sind.
Wir wählen $99999.99 seit 23 < 24.

-1
  1. Berechnen Sie die maximale Länge des Preises, nehmen Sie an, es ist etwa 0,00001. (Sie können das tun, indem Sie £ 0.10 in die Währung ändern und dann das 10-Fuß-Protokoll davon nehmen, um seine Ceil und diese Potenz von 10 zu erhalten).

Eg: £ 0.10 = 17,1421309 ¥

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

die Nummer für die Ziffer einstellen, fügen Sie 1, rund bis 50, subtrahieren 1:

174055 -> (round ((174.055/100 + 1)/50) * 50-1) * 100 = 174900

Einfach und einfach.

+0

Sie haben die Frage nicht gelesen –

+0

@Tomgullen Ich habe es gelesen, ich wollte nur nicht zu sehr ins Detail gehen, meine Schuld. Lies mein Update. – Kicsi

1

Hier ist eine hässliche Antwort:

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') 

EDIT: Das ist ein bisschen bessere Lösung, mit 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