Esiste un'unica rappresentazione dei dati che funziona per tutte le valute (anche se diverse da Dollari, Euro e Sterline)?


12

Posso trovare molte domande sulle biblioteche da utilizzare per rappresentare gli importi in alcune valute. E sulla secolare questione del perché non dovresti conservare la valuta come un numero in virgola mobile IEEE 754. Ma non riesco a trovare altro. Sicuramente c'è molto altro da sapere sulla valuta nell'uso del mondo reale. Sono particolarmente interessato a ciò che dovresti sapere per rappresentarlo nell'uso fisico (ad esempio, con il dollaro, non hai mai una precisione inferiore a $ 0,01, consentendo la rappresentazione come numero intero di centesimi).

Ma è difficile fare ipotesi su quanto sia versatile il tuo programma quando le uniche valute che conosci sono quelle popolari occidentali (come il dollaro, l'euro e la sterlina). Cos'altro è la conoscenza rilevante in una prospettiva puramente programmatica? Non sono preoccupato per l'argomento della conversione.

In particolare, cosa dobbiamo sapere per poter memorizzare i valori in alcune valute e stamparli?


2
Non tutti i programmatori lavorano in settori che manipolano gli importi in valuta.
whatsisname

4
Oh, certo. Ma si può dire di quasi tutto. Penso che possiamo supporre che coloro che troverebbero utile questa domanda sarebbero quelli che lavorano con la valuta.
Kat

5
Ho lavorato molto per lo sviluppo di banche e altre società di servizi finanziari a New York. E posso praticamente garantirti che non esiste una risposta "chiusa" alla tua domanda. Potresti anche chiedere "quanta matematica devo sapere?" Ad esempio, negli anni '90 i prezzi delle azioni sono passati dall'ottava e 256a decimale, richiedendo molte riprogrammazioni. Chi avrebbe potuto immaginare che sarebbe successo? Devi solo capire il business che le tue applicazioni supportano e come rappresentare al meglio i dati (in questo caso la valuta) per supportare quelle esigenze di business.
John Forkosh,

4
Il mio 0.02: il prezzo è una cosa. La valuta è un'altra.
Machado,

3
Ho pensato: Oh, ci deve essere un denominatore comune per tutte le valute. Ma forse no. La sterlina è attualmente 1⁄100 di sterlina, ma era 1⁄240 di sterlina. Quindi non solo hai una divisione di 1/240, ma hai una data di scambio e forse un tasso di cambio per vecchio pence non ancora cambiato. en.wikipedia.org/wiki/Penny_sterling Non farmi nemmeno iniziare con le conchiglie cowry! en.wikipedia.org/wiki/Shell_money o il fatto che il denaro richieda credenza per diventare reale: en.wikipedia.org/wiki/Money Ottima domanda anche se non si adatta bene a StackExchange!
GlenPeterson,

Risposte:


24

ad esempio, con il dollaro, non hai mai una precisione inferiore a $ 0,01

Oh veramente? inserisci qui la descrizione dell'immagine

la secolare questione del perché non dovresti conservare la valuta come un numero in virgola mobile IEEE 754.

inserisci qui la descrizione dell'immagine

Non esitate a memorizzare pollici in numeri in virgola mobile IEEE 754 . Conservano esattamente come ti aspetteresti.

Non esitate a memorizzare qualsiasi somma di denaro in numeri a virgola mobile IEEE 754 che è possibile memorizzare utilizzando i segni di spunta che dividono un righello in frazioni di pollice.

Perché? Perché quando usi IEEE 754 è così che lo stai memorizzando.

Il fatto è che i pollici sono divisi a metà. La cosa sulla maggior parte dei tipi di valuta è che sono divisi in decimi (alcuni tipi non lo sono ma restiamo concentrati).

Questa differenza non sarebbe poi così confusa se non che, per la maggior parte dei linguaggi di programmazione, l'input e l'output dai numeri in virgola mobile IEEE 754 sono espressi in decimali! Il che è molto strano perché non sono memorizzati in decimali.

Per questo motivo non si arriva mai a vedere come i bit fanno cose strane quando si chiede al computer di memorizzare 0.1. Vedi la stranezza solo quando fai matematica contro di essa e ha strani errori.

Da java efficace di Josh Bloch :

System.out.println(1.03 - .42);

produce 0.6100000000000001

Quello che dice di più di questo non è il 1modo di sedersi laggiù a destra. Sono i numeri strani che dovevano essere usati per ottenerlo. Invece di usare l'esempio più popolare 0.1, dobbiamo usare un esempio che mostri il problema ed eviti l'arrotondamento che lo nasconderebbe.

Ad esempio, perché funziona?

System.out.println(.01 - .02);

produce -0.01

Perché siamo stati fortunati.

Odio i problemi che sono difficili da diagnosticare perché a volte divento "fortunato".

IEEE 754 semplicemente non può memorizzare 0,1 con precisione. Ma se gli chiedi di memorizzare 0.1 e poi gli chiedi di stampare, mostrerà 0.1 e penserai che tutto vada bene. Non va bene, ma non puoi vederlo perché sta arrotondando per tornare a 0.1.

Alcune persone confondono il diavolo con gli altri chiamando queste discrepanze arrotondando gli errori. No, questi non sono errori di arrotondamento. L'arrotondamento sta facendo ciò che dovrebbe e trasformando ciò che non è un decimale in un decimale in modo che possa essere stampato sullo schermo.

Ma ciò nasconde la discrepanza tra la modalità di visualizzazione del numero e la modalità di memorizzazione. L'errore non si è verificato quando si è verificato l'arrotondamento. È successo quando hai deciso di inserire un numero in un sistema che non è in grado di memorizzarlo con precisione e hai pensato che fosse memorizzato esattamente quando non lo era.

Nessuno si aspetta che π memorizzi esattamente in una calcolatrice e riescono a lavorarci bene. Quindi il problema non riguarda nemmeno la precisione. Si tratta della precisione attesa. I computer visualizzano un decimo come 0.1i nostri calcolatori, quindi ci aspettiamo che memorizzino un decimo perfettamente come fanno i nostri calcolatori. Non lo fanno. Il che è sorprendente, poiché i computer sono più costosi.

Lascia che ti mostri la mancata corrispondenza:

inserisci qui la descrizione dell'immagine

Si noti che 1/2 e 0,5 si allineano perfettamente. Ma 0.1 non si allinea. Sicuramente puoi avvicinarti se continui a dividere per 2 ma non lo colpirai mai esattamente. E abbiamo bisogno di sempre più bit ogni volta che ci dividiamo per 2. Quindi rappresentare 0,1 con qualsiasi sistema che divide per 2 richiede un numero infinito di bit. Il mio disco rigido non è poi così grande.

Quindi IEEE 754 smette di provare quando si esauriscono i bit. Il che è bello perché ho bisogno di spazio sul mio disco rigido per ... foto di famiglia. No davvero. Foto di famiglia : P

Ad ogni modo, ciò che digiti e ciò che vedi sono i decimali (a destra) ma ciò che memorizzi è bicimali (a sinistra). A volte quelli sono perfettamente uguali. A volte no. A volte sembra che siano gli stessi quando semplicemente non lo sono. Questo è l'arrotondamento.

In particolare, cosa dobbiamo sapere per poter archiviare valori in alcune valute e stamparle?

Per favore, se stai gestendo il mio denaro basato su decimali, non usare float o doppi.

Se sei sicuro che cose come i decimi di penny non saranno coinvolte, allora conserva solo i penny. Se non lo sei, scopri quale sarà la più piccola unità di questa valuta e usala. Se non puoi, usa qualcosa come BigDecimal .

Il mio patrimonio netto si adatterà probabilmente sempre a un intero a 64 bit, ma cose come BigInteger funzionano bene per progetti più grandi di così. Sono solo più lenti dei tipi nativi.

Capire come conservarlo è solo metà del problema. Ricorda che devi anche essere in grado di visualizzarlo. Un buon design separerà queste due cose. Il vero problema con l'utilizzo di float qui è che queste due cose sono messe insieme.

inserisci qui la descrizione dell'immagine


6
Non stavo davvero cercando un'altra spiegazione del perché IEEE 754 non funziona per soldi. Nel PO ho menzionato che ciò è stato ben spiegato altrove. Allo stesso modo, c'è un motivo per cui ho usato il termine "uso fisico". Vale a dire perché mentre i prezzi del gas, i valori di borsa, ecc. Potrebbero avere una precisione arbitraria, i soldi fisici (e il vasto numero di transazioni degli utenti) non superano le centinaia di posti (e vari software vogliono rappresentare solo ciò che può essere pagato con denaro fisico). Un'informazione che mi chiedevo era se esistessero valute che andavano in posizioni più decimali.
Kat

3
La "stranezza" del virgola mobile non si limita solo alla metà e al 1/10 di. L'aspetto "virgola mobile" nel nome provoca anche risultati talvolta imprevisti.
whatsisname

6
Prima della decimalizzazione la valuta del Regno Unito era sterline, scellini e pence, (£ sd), con £ 1 == 20s, 1s = 12d quindi £ 1 = 240d quindi 1d = 0,0046666666666 .. quindi non poteva nemmeno essere rappresentato come un decimale. Prima di unirsi all'euro, la Lira italiana ha superato i 2346,4 (nel 2001) a $ USA, quindi cose come i salari e i prezzi delle case a volte hanno raggiunto il limite superiore dei singoli galleggianti di precisione e le cifre economiche hanno raggiunto i livelli più alti dei doppi.
Steve Barnes

2
Direi / sottolineerei che la valuta è una cosa e il prezzo è un'altra cosa. Puoi avere più di $ 0,01 di precisione nei prezzi, ma non puoi pagare in modo efficace, con quella precisione.
Machado,

1
Inoltre, foto di famiglia . PFT. :)
Machado,

10

Posso trovare molte domande sulle biblioteche da utilizzare per rappresentare gli importi in alcune valute.

Le "librerie" non sono necessarie a meno che la libreria standard della tua lingua non sia carente in alcuni tipi di dati, come spiegherò.

Sicuramente c'è molto altro da sapere sulla valuta nell'uso del mondo reale. Sono particolarmente interessato a ciò che dovresti sapere per rappresentarlo nell'uso fisico (ad esempio, con il dollaro, non hai mai una precisione inferiore a $ 0,01, consentendo la rappresentazione come numero intero di centesimi).

Molto semplicemente, hai bisogno di decimali in virgola fissa , non decimali in virgola mobile. Ad esempio, la classe BigDecimal di Java potrebbe essere utilizzata per memorizzare un importo in valuta. Altri linguaggi moderni hanno tipi simili incorporati, tra cui C # e Python . Le implementazioni variano, ma in genere memorizzano un numero come numero intero, con la posizione decimale come membro di dati separato. Ciò fornisce la precisione esatta, anche quando si esegue l'aritmetica che darebbe residui dispari (ad es. 0,0000001) con numeri in virgola mobile IEEE.

In particolare, cosa dobbiamo sapere per poter archiviare valori in alcune valute e stamparle?

Ci sono alcuni punti importanti.

  1. Utilizzare un tipo decimale effettivo anziché in virgola mobile.

  2. Comprendi che un importo in valuta ha due componenti: un valore (5.63) e un codice o tipo di valuta (USD, CAD, GBP, EUR, ecc.). A volte puoi ignorare il codice valuta, altre volte è vitale. Cosa succede se stai lavorando su un sistema finanziario o al dettaglio / e-commerce che consente più valute? Cosa succede se stai cercando di prelevare denaro da un cliente in CAD, ma vogliono pagare con MXN? È necessario un tipo di "denaro" con un codice valuta e un importo in valuta per poter mescolare questi valori (anche il tasso di cambio, ma non voglio andare troppo lontano su una tangente). Allo stesso tempo, il mio software di finanza personale non deve mai preoccuparsi di questo perché tutto è in USD ( può mescolare valute, ma non ne ho mai bisogno).

  3. Mentre in pratica una valuta può avere un'unità fisica più piccola (CAD e USD hanno centesimi, JPY è solo ... Yen), è possibile ridurla. La risposta di CandiedOrange sottolinea i prezzi del carburante in decimi di centesimo. Le mie tasse sulla proprietà sono valutate come mulini per dollaro o decimi di centesimo (1/1000 di un dollaro USD). Non ti limitare a $ 0,01. Sebbene sia possibile visualizzare tali valori per la maggior parte del tempo, i tipi dovrebbero consentire valori più piccoli (i tipi decimali sopra indicati fanno).

  4. I calcoli intermedi certamente devono consentire una precisione maggiore di un singolo centesimo. Ho lavorato su sistemi di vendita al dettaglio / e-commerce in cui i valori interni sono stati arrotondati a $ 0,00000001 internamente. La precisione infinita non è in genere supportata da tipi decimali (o SQL), quindi è necessario un certo limite. Ad esempio, la divisione di 1/3 utilizzando BigDecimal di Java genererà un'eccezione senza un RoundingMode o MathContext specificato perché il valore non può essere rappresentato esattamente.

    Comunque, questo è fondamentale in alcuni casi. Supponiamo che tu abbia un utente con sei articoli nel suo carrello e lui va a dare un'occhiata. Il tuo sistema deve calcolare le tasse e lo fa per articolo perché gli articoli possono essere tassati in modo diverso. Se si arrotondano le imposte per ogni articolo, è possibile che si verifichino errori di arrotondamento a livello di transazione / carrello. Un approccio per risolvere questo problema potrebbe essere quello di archiviare le tasse in più decimali per articolo, ottenere il totale per l'intera transazione e tornare indietro e arrotondare ogni articolo in modo che l'imposta totale sia corretta (forse un articolo viene arrotondato per eccesso, un altro per difetto).

La cosa importante da capire da tutto ciò è che qualcosa di così importante come arrotondare i penny può essere molto importante per le persone giuste (ad esempio alcuni dei miei precedenti clienti che hanno dovuto pagare le tasse di vendita del governo per conto dei loro clienti). Tuttavia, questi sono tutti problemi risolti. Tieni a mente i punti precedenti e fai qualche esperimento da solo, e imparerai facendo.


Il 2, penso che il tasso di cambio sia sufficiente per ottenere almeno il proprio numero. Devi considerare che le tariffe cambiano nel tempo, che ha un paio di modi diversi di gestione.
Izkata,

2
+1. Inoltre, le valute cambiano nel tempo. In Brasile abbiamo avuto ripetutamente cambi di valuta negli anni '80 e '90, tagliando gli zeri e rinominando la valuta quando necessario a causa dell'inflazione fuori controllo. Ciò significa che ogni aspetto di una valuta può cambiare nel tempo.
Machado,

@Izkata certamente, ho lavorato su sistemi che cambiano valute. Volevo toccare l'argomento in quanto è rilevante. Tuttavia, questo non è il punto focale della domanda e probabilmente potrei scrivere un'altra risposta purché questa sia sul tema dello scambio di valuta.

"Le librerie" non sono necessarie a meno che la libreria standard della tua lingua non sia carente in alcuni tipi di dati, come spiegherò. " Le valute possono avere metà, quarti, decimi, ottavi, ecc. Ciò significa che abbiamo almeno bisogno di una rappresentazione decimale per loro. Ma siamo assolutamente certi che non ci sono valute con un pezzo intero di 1/3?
Daniel McLaury

4

Un luogo in cui molti sviluppatori devono confrontarsi con un'unica rappresentazione di dati per qualsiasi valuta è per gli acquisti in-app per le applicazioni iOS. Il tuo cliente può essere collegato a un negozio in quasi tutti i paesi del mondo. E in quella situazione, ti verrà dato un prezzo di acquisto composto da un doppio numero di precisione e un codice valuta.

Devi essere consapevole che i numeri potrebbero essere grandi. Ci sono valute in cui l'equivalente di dire dieci dollari è più di 100.000 unità. E siamo fortunati che al momento non ci siano valute come il dollaro dello Zimbabwe, dove potresti avere cento trilioni di banconote!

Per visualizzare le valute, avrai bisogno di alcune librerie: non hai alcuna possibilità di fare tutto da solo. La visualizzazione dipende da due cose: il codice valuta e le impostazioni internazionali dell'utente. Pensa a come verranno visualizzati i dollari USA e i dollari canadesi con le impostazioni locali statunitensi e canadesi: negli Stati Uniti, hai $ vs CAN $ e in Canada hai US $ contro $. Spero che sia integrato nel sistema operativo o che tu abbia una buona libreria.

Per i calcoli, qualsiasi calcolo terminerà con una fase di arrotondamento. Dovrai scoprire come eseguire legalmente tale arrotondamento . Non è un problema di programmazione, è un problema legale. Ad esempio, se si calcola l'IVA nel Regno Unito, è necessario calcolare l'imposta per articolo o per riga di articolo e arrotondarla per centesimo. A cosa ti rivolgi dipende dalla valuta. Ma le regole ovviamente dipendono dal paese. Non puoi aspettarti che un calcolo legalmente corretto nel Regno Unito sia legalmente corretto in Giappone e viceversa.


0

In particolare, cosa dobbiamo sapere per poter memorizzare i valori in alcune valute e stamparli?

  • "per memorizzare valori" : un tipo di dati con numero a virgola fissa e un tipo di valuta. Penso che questi siano abbastanza ovvi. La memorizzazione su un numero a virgola fissa potrebbe comportare alcuni arrotondamenti e modificare il valore. Il calcolo della valuta sarebbe un problema diverso.
  • "per stamparli" : impostazioni locali dell'utente. Se sei fortunato, ottieni la libreria standard per fare tutto, ad esempio simbolo di valuta, separatore di migliaia, separatore decimale, precisione, ecc.

Alcuni problemi di esempio relativi alle impostazioni locali:

  • 100 USD nelle impostazioni internazionali degli Stati Uniti dovrebbero essere $ 100,00, in altre impostazioni locali con punto come separatore decimale sarebbe $ 100,00.
  • Alcuni paesi usano una miriade anziché migliaia per raggruppare i numeri, ad esempio invece di 10.000,00 sarebbe solo 1.0000,00
  • Per motivi pratici, le persone non stampano tutti i numeri per piccole valute, ad esempio invece di $ 1.000.000.000,00, vogliono solo che tu stampi $ 1 miliardo.

Un altro potenziale problema è anche se si memorizza correttamente la valuta in un numero in virgola fissa, potrebbe essere necessario convertirla in un numero in virgola mobile poiché la libreria utilizzata per la stampa supporta solo virgola mobile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.