2014-05-22 12 views
5

Data una valuta di base di GBP £, e un tavolo di altra moneta accettata in un negozio:Trova il bel numero più vicino

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

Abbiamo un metodo di lavoro che converte una data quantità di GBP Pence (AKA cents) in Currency X cents. Dato un prezzo di 999 (£ 9,99), per le monete di cui sopra sarebbe tornare:

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

Questo è tutto lavoro assolutamente bene. Abbiamo poi un metodo di Format Currency che tutti li converte in bei numeri alla ricerca:

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

Ora il problema che vogliamo risolvere, è quello di arrotondare tali importi alle meaningful pretty number in un algoritmo di uso generale dato le informazioni di cui sopra.

Questo serve a due importanti vantaggi:

  • I prezzi per la maggior parte delle valute dovrebbe apparire statico per i visitatori nel corso del tempo breve-medio termine cornici
  • presenta al visitatore con un prezzo culturalmente meaningul che incoraggia le vendite

un meaningful number è quella in cui la più piccola unità visualizzata non è inferiore al valore di dire £ 0,10, e un pretty number è uno che termina in 49 o 0.123.081,672131 millions. uscite Esempio:

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 

So che è possibile fare questo con un unico algoritmo con tutte le informazioni fornite, ma sto lottando per capire anche da dove cominciare. Qualcuno può mostrarmi come ottenerlo o dare dei suggerimenti?

Si prega di notare, la memorizzazione di una regola di formattazione generale per ciascuna valuta non è adeguata perché, ad esempio, si assuma il prezzo di Bitcoin 10x, la regola di formattazione dovrà essere aggiornata. Sto cercando una soluzione che non ha bisogno di alcuna manutenzione/controllo manuale.

+0

Credo che la tua definizione è sbagliata, dal 0,01 dollari è meno di .10 libbre –

+0

(o anche 0,09 dollari) –

risposta

4

Per un dato valore decimale X, si desidera trovare il più piccolo intero Y tale che YA + B il più vicino possibile a X, per alcuni dati A e B. E.g. nel caso del dollaro, hai A = .5 e B = .49.

In generale, per il vostro problema, A e B può essere calcolato applicando la formula:

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 

Nota che senza la condizione in più, dal momento che 0,09 dollari è inferiore a 0,10 sterline, otterremmo 14,9 come il risultato per 16,86 dollari.

Con qualche trasformazione otteniamo

Y ~ (X - B)/A 

E poiché Y è intero, abbiamo

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

Il risultato è quindi YA + B.

1
  • Converti £0.10 alla valuta corrente per determinare la più piccola cifra visualizzabile (SDD)
    (delimitata dal numero di cifre disponibili in tale valuta).

  • Ora abbiamo praticamente hanno 3 scelte di numeri:

    • ... (3rdSDD-1) 9 9 (se 3rdSDD è 0, sarà ovviamente trasportare da 4thSDD e così via, come sottrazione funziona normalmente)

      faremo scegliere questo quando 10*2ndSDD + 1stSDD < 24

    • ... 3rdSDD 4 9

      Sceglieremo questo quando 24 <= 10*2ndSDD + 1stSDD < 74

    • ... 3rdSDD 9 9

      Sceglieremo questo quando 74 < 10*2ndSDD + 1stSDD

  • Dovrebbe essere banale per capirlo da qui.
    Alcune moltiplicazioni e moduli per ottenere 2ndSDD e 1stSDD.
    Sottrazione di base per ottenere ... (3rdSDD-1).
    Alcune dichiarazioni if ​​per scegliere uno dei casi sopra elencati.

Esempio:

Per $16.86, le nostre 3 scelte sono $15.99, $16.49 e $16.99.
Selezioniamo $16.99 dal 74 < 86.

Per €12.33, le nostre scelte sono 3 €11.99, €12.49 e €12.99.
Selezioniamo €12.49 dal 24 <= 33 < 74.

Per ¥1755, le nostre scelte sono 3 ¥1699, ¥1749 e ¥1799.
Selezioniamo ¥1749 dal 24 <= 55 < 74.

Per ฿0.03482570, le nostre scelte sono 3 ฿0.0299, ฿0.0349 e ฿0.0399.
Selezioniamo ฿0.0349 dal 24 <= 48 < 74.

E, solo per mostrare il riporto:

Per $100000.23, le nostre scelte sono 3 $99999.99, $100000.49 e $100000.99.
Selezioniamo $99999.99 dal 23 < 24.

-1
  1. Calcolare la lunghezza massima del prezzo, supponendo che sia qualcosa come 0.00001. (Puoi farlo cambiando £ 0.10 nella valuta, poi prendendoti il ​​registro di base di 10, ottenendo il suo ceil e quella potenza di 10).

Ad esempio: £ 0.10 = 17,1,421309 millions ¥

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

Regolare il numero per la cifra, aggiungere 1, rotondo a 50, sottrarre 1:

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

Semplice e semplice.

+0

Non hai letto la domanda –

+0

@Tomgullen. L'ho letto, non volevo andare troppo nei dettagli, colpa mia. Leggi il mio aggiornamento. – Kicsi

1

Ecco una risposta brutta:

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: questo è un po 'soluzione migliore, utilizzando 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 
Problemi correlati