it-swarm.it

Usa virgola mobile o decimale per l'importo in dollari dell'applicazione contabile?

Stiamo riscrivendo il nostro sistema di contabilità legacy in VB.NET e SQL Server. Abbiamo introdotto un nuovo team di programmatori .NET/SQL per eseguire la riscrittura. La maggior parte del sistema è già completata con gli importi in dollari utilizzando Floats. Il linguaggio di sistema legacy, che ho programmato, non aveva un Float, quindi probabilmente avrei usato un decimale.

Qual è la tua raccomandazione?

Il tipo di dati Float o Decimal deve essere utilizzato per importi in dollari?

Quali sono alcuni dei pro e contro per entrambi?

One Con menzionato nella nostra mischia giornaliera era che bisogna stare attenti quando si calcola un importo che restituisce un risultato superiore a due posizioni decimali. Sembra che dovrai arrotondare l'importo a due posizioni decimali.

Un altro Con è tutte le visualizzazioni e gli importi stampati devono avere una dichiarazione di formato che mostra due posizioni decimali. Ho notato alcune volte che ciò non è stato fatto e le quantità non sembravano corrette. (cioè 10.2 o 10.2546)

Un professionista è che il Float occupa solo 8 byte su disco, dove il decimale occupa 9 byte (decimale 12,2) 

74
Gerhard Weiss

Il tipo di dati Float o Decimal deve essere utilizzato per importi in dollari?

La risposta è facile Non galleggia mai. MAI !

I float erano secondo IEEE 754 sempre binari, solo i nuovi standard (IEEE 754R formati decimali definiti. Molte parti binarie frazionarie non possono mai eguagliare la rappresentazione decimale esatta.
Qualsiasi numero binario può essere scritto come m/2^n (m, n interi positivi), qualsiasi numero decimale come m/(2^n*5^n).
Siccome i binari non hanno il primo factor 5, tutti i numeri binari possono essere esattamente rappresentati da decimali, ma non viceversa.

0.3 = 3/(2^1 * 5^1) = 0.3

0.3 = [0.25/0.5] [0.25/0.375] [0.25/3.125] [0.2825/3.125]

          1/4         1/8         1/16          1/32

Quindi si finisce con un numero più alto o più basso del numero decimale dato. Sempre.

Perché importa? Arrotondamento.
L'arrotondamento normale indica 0..4 in basso, 5..9 in alto. Quindi fa importa se il risultato è O 0.049999999999.... o 0.0500000000... Potresti sapere che significa 5 cent, ma il computer non lo sa e arrotonda 0.4999... giù (errato) e 0.5000... su (a destra).
Dato che il risultato dei calcoli in virgola mobile contiene sempre piccoli termini di errore, la decisione è pura fortuna. Diventa impossibile se si desidera una gestione decimale round-to-even con numeri binari.

Poco convinta ? Insisti sul fatto che nel tuo sistema di account tutto sia perfettamente ok?
Attività e passività sono uguali? Ok, quindi prendi ciascuno dei numeri formattati di ogni voce, analizzali e sommi con un sistema decimale indipendente! Confrontalo con la somma formattata.
Oops, c'è qualcosa di sbagliato, non è vero? 

Per questo calcolo, era richiesta estrema accuratezza e fedeltà (abbiamo usato Oracle's FLOAT) in modo da poter registrare il "miliardesimo di un centesimo" in modo accurato.

Non aiuta contro questo errore. Perché tutte le persone automaticamente presumono che il computer sommi bene, praticamente nessuno controlla in modo indipendente.

105
TSK
41
Nakilon

Per prima cosa dovresti leggere questo Cosa ogni scienziato informatico dovrebbe sapere sull'aritmetica in virgola mobile . Quindi dovresti davvero prendere in considerazione l'utilizzo di un certo tipo di numero fisso/numero di precisione arbitrario pacchetto (ad esempio Java BigNum, modulo decimale di python) altrimenti ti troverai in un mondo di dolore. Quindi capire se è sufficiente utilizzare il tipo decimale SQL nativo. 

Floats/doubles esistono (ed) per esporre il veloce x87 fp che ora è praticamente obsoleto. Non usarli se ti interessa la precisione dei calcoli e/o non compensare completamente i loro limiti.

22
Rich Schuler

Come ulteriore avviso, SQL Server e il framework .Net utilizzano un diverso algoritmo predefinito per l'arrotondamento. Assicurati di controllare il parametro MidPointRounding in Math.Round (). .Net framework utilizza l'algoritmo Bankers per impostazione predefinita e SQL Server utilizza Symmetric Algorithmic Rounding. Controlla l'articolo di Wikipedia qui

10
Darrel Miller

Chiedi ai tuoi contabili! Ti guarderanno male per aver usato il galleggiante. Come qualcuno pubblicato prima, usa SOLAMENTE il float se non ti interessa la precisione. Anche se sarei sempre contraria quando si tratta di soldi.

Nel software di contabilità NON è accettabile un galleggiante. Usa decimale con 4 punti decimali.

7
Ricardo C

I punti in virgola mobile hanno numeri irrazionali inattesi.

Ad esempio non puoi memorizzare 1/3 come decimale, sarebbe 0.3333333333 ... (e così via)

I float sono in realtà memorizzati come valore binario e potenza di 2 esponenti.

Quindi 1,5 viene memorizzato come 3 x 2 in -1 (o 3/2)

Usando questi esponenti di base-2 crea alcuni numeri irrazionali dispari, ad esempio:

Converti 1.1 in un float e poi riconvertirlo di nuovo, il tuo risultato sarà qualcosa come: 1.0999999999989

Questo perché la rappresentazione binaria di 1.1 è in realtà 154811237190861 x 2 ^ -47, più di un doppio in grado di gestire.

Ulteriori informazioni su questo problema su il mio blog , ma fondamentalmente, per l'archiviazione, si sta meglio con i decimali.

Sul server Microsoft SQL si ha il tipo di dati money, che di solito è il migliore per l'archiviazione finanziaria. È preciso a 4 posizioni decimali.

Per i calcoli si ha più di un problema - l'inaccuratezza è una piccola frazione, ma la metti in una funzione di potere e diventa rapidamente significativa. 

Tuttavia, i decimali non sono molto buoni per qualsiasi tipo di matematica, ad esempio non esiste un supporto nativo per i poteri decimali.

6
Keith

Un po 'di background qui ....

Nessun sistema numerico può gestire tutti i numeri reali con precisione. Tutti hanno i loro limiti e questo include sia il punto di virgola IEEE standard che i decimali con segno. Il punto mobile IEEE è più preciso per bit utilizzato, ma non importa qui.

I numeri finanziari si basano su secoli di pratica di carta e penna, con convenzioni associate. Sono ragionevolmente precisi, ma, soprattutto, sono riproducibili. Due ragionieri che lavorano con vari numeri e tariffe dovrebbero venire con lo stesso numero. Qualsiasi spazio per discrepanza è spazio per frode.

Pertanto, per i calcoli finanziari, la risposta giusta è qualunque dia la stessa risposta di un CPA che è bravo in aritmetica. Questa è l'aritmetica decimale, non il punto mobile IEEE.

5
David Thornley

Utilizzare il tipo decimal del server SQL.

Non usare denaro o float.

il denaro usa 4 cifre decimali, è più veloce dell'uso decimale MA soffre di alcuni ovvi e alcuni problemi non ovvi con l'arrotondamento ( vedi questo problema di connessione

5
Mitch Wheat

Quello che raccomanderei è usare interi a 64 bit che memorizzano l'intero importo in centesimi.

5
Joshua

I float non sono rappresentazioni esatte, sono possibili problemi di precisione, ad esempio quando si aggiungono valori molto grandi e molto piccoli. Ecco perché i tipi decimali sono raccomandati per la valuta, anche se il problema di precisione potrebbe essere sufficientemente raro.

Per chiarire, il tipo decimale 12,2 memorizzerà esattamente quelle 14 cifre, mentre il float non lo farà poiché utilizza internamente una rappresentazione binaria. Ad esempio, 0,01 non può essere rappresentato esattamente da un numero in virgola mobile - la rappresentazione più vicina è in realtà 0,0099999998

4
Niall

Per un sistema bancario che ho aiutato a sviluppare, ero responsabile per la parte "interessi maturati" del sistema. Ogni giorno, il mio codice calcolava quanti interessi erano stati accumulati (guadagni) sul saldo quel giorno.

Per questo calcolo è stata richiesta estrema accuratezza e fedeltà (abbiamo utilizzato il FLOAT di Oracle) in modo da poter registrare il "miliardesimo di un centesimo" accumulato.

Quando si è trattato di "capitalizzare" l'interesse (cioè di ripagare l'interesse sul proprio conto), l'importo è stato arrotondato al centesimo. Il tipo di dati per i saldi dell'account era di due cifre decimali. (In effetti era più complicato in quanto era un sistema multivaluta che poteva funzionare in molti decimali - ma abbiamo sempre arrotondato il "penny" di quella valuta). Sì, là dove "le frazioni" di perdita e guadagno, ma quando le cifre dei computer sono state attualizzate (soldi pagati o pagati) erano sempre valori monetari REALI.

Questo ha soddisfatto i ragionieri, i revisori dei conti e i tester.

Quindi, controlla con i tuoi clienti. Ti diranno le loro regole e pratiche bancarie/contabili.

4
Guy

L'unica ragione per usare Float per soldi è se non ti importa delle risposte accurate. 

4
David Singer

Un'altra cosa di cui dovresti essere a conoscenza nei sistemi di contabilità è che nessuno dovrebbe avere accesso diretto ai tavoli. Ciò significa che tutti gli accessi al sistema di contabilità devono avvenire tramite stored procs. Questo è prevenire le frodi non solo gli attacchi SQl. Un utente interno che vuole commettere una frode non dovrebbe avere la possibilità di modificare direttamente i dati nelle tabelle del database, mai. Questo è un controllo interno critico sul tuo sistema. Vuoi davvero che qualche dipendente scontento vada sul backend del tuo database e inizi a scriverli? O nascondere che hanno approvato una spesa per un venditore non autorizzato quando non hanno l'autorizzazione di approvazione? Solo due persone nell'intera organizzazione dovrebbero essere in grado di accedere direttamente ai dati nel database finanziario, nel dba e nel backup. Se disponi di molti dbas, solo due di questi dovrebbero avere questo accesso.

Dico questo perché se i tuoi programmatori usavano fluttuare in un sistema di contabilità, probabilmente non conoscevano completamente l'idea dei controlli interni e non li consideravano nei loro sforzi di programmazione.

3
HLGEM

Ancora meglio che usare i decimali sta usando semplicemente vecchi interi (o forse una sorta di bigint). In questo modo hai sempre la massima precisione possibile, ma la precisione può essere specificata. Ad esempio il numero 100 potrebbe significare 1.00, che è formattato in questo modo:

int cents = num % 100;
int dollars = (num - cents) / 100;
printf("%d.%02d", dollars, cents);

Se ti piace avere maggiore precisione, puoi modificare il valore 100 in un valore più grande, come: 10 ^ n, dove n è il numero di decimali.

3
Peter Stuifzand

Tra le 100 frazioni n/100, dove n è un numero naturale tale che 0 <= n e n <100, solo quattro possono essere rappresentati come numeri in virgola mobile. Dai un'occhiata all'output di questo programma C:

#include <stdio.h>

int main()
{
    printf("Mapping 100 numbers between 0 and 1 ");
    printf("to their hexadecimal exponential form (HEF).\n");
    printf("Most of them do not equal their HEFs. That means ");
    printf("that their representations as floats ");
    printf("differ from their actual values.\n");
    double f = 0.01;
    int i;
    for (i = 0; i < 100; i++) {
        printf("%1.2f -> %a\n",f*i,f*i);
    }
    printf("Printing 128 'float-compatible' numbers ");
    printf("together with their HEFs for comparison.\n");
    f = 0x1p-7; // ==0.0071825
    for (i = 0; i < 0x80; i++) {
        printf("%1.7f -> %a\n",f*i,f*i);
    }
    return 0;
}
2
Lars Bohl

Puoi sempre scrivere qualcosa come un tipo di denaro per .Net.

Date un'occhiata a questo articolo: Un tipo di denaro per il CLR - L'autore ha fatto un lavoro eccellente a mio parere.

2
Tomer Pintel

Stavo usando il tipo di denaro di SQL per la memorizzazione di valori monetari. Recentemente, ho dovuto lavorare con un numero di sistemi di pagamento online e ho notato che alcuni di loro usano numeri interi per memorizzare valori monetari. Nei miei progetti attuali e nuovi ho iniziato a utilizzare numeri interi e sono abbastanza soddisfatto di questa soluzione.

2
George

Probabilmente vorrai utilizzare una qualche forma di rappresentazione a virgola fissa per i valori di valuta. Dovrai anche indagare sull'arrotondamento del Banker (noto anche come "round half even".) Evita i pregiudizi che esistono nel consueto metodo "round half up".

1
user6931

Hai preso in considerazione l'utilizzo del tipo di dati monetari per archiviare importi in dollari?

Per quanto riguarda il Con, il decimale occupa un altro byte, direi che non gli interessa. In 1 milione di righe utilizzerai solo 1 altro MB e l'archiviazione è molto economica in questi giorni.

1
Espo

Qualunque cosa tu faccia, devi fare attenzione agli errori di arrotondamento. Calcola utilizzando un grado di precisione maggiore di quello visualizzato.

1
1800 INFORMATION

I tuoi contabili vorranno controllare come arrotondare. Usare float significa che sarai costantemente arrotondato, di solito con un'istruzione di tipo FORMAT (), che non è il modo in cui vuoi farlo (usa invece floor/ceiling).

Hai dei tipi di dati di valuta (denaro, smallmoney), che dovrebbero essere usati al posto di float o reali. Memorizzare decimali (12,2) eliminerà i tuoi arrotondamenti, ma li eliminerà anche durante i passaggi intermedi - che in realtà non è quello che vorrai assolutamente in un'applicazione finanziaria.

0
David T. Macknet

Questo è un eccellente articolo che descrive quando usare float e decimal . Float memorizza un valore approssimativo e le cifre decimali memorizzano un valore esatto.

In breve, valori esatti come il denaro dovrebbero usare decimali e valori approssimativi come le misurazioni scientifiche dovrebbero usare il float. 

Ecco un esempio interessante che mostra che sia il float che il decimale sono in grado di perdere precisione. Quando si aggiunge un numero che non è un numero intero e quindi si sottrae lo stesso numero con virgola mobile, si perde la precisione mentre il numero decimale non lo è:

    DECLARE @Float1 float, @Float2 float, @Float3 float, @Float4 float; 
    SET @Float1 = 54; 
    SET @Float2 = 3.1; 
    SET @Float3 = 0 + @Float1 + @Float2; 
    SELECT @Float3 - @Float1 - @Float2 AS "Should be 0";

Should be 0 
---------------------- 
1.13797860024079E-15

Quando si moltiplica un numero intero non intero e si divide per lo stesso numero, i decimali perdono precisione mentre i float no.

DECLARE @Fixed1 decimal(8,4), @Fixed2 decimal(8,4), @Fixed3 decimal(8,4); 
SET @Fixed1 = 54; 
SET @Fixed2 = 0.03; 
SET @Fixed3 = 1 * @Fixed1 / @Fixed2; 
SELECT @Fixed3 / @Fixed1 * @Fixed2 AS "Should be 1";

Should be 1 
--------------------------------------- 
0.99999999999999900
0
BrokeMyLegBiking

Usa sempre decimale. Float ti fornirà valori inaccurati a causa di problemi di arrotondamento.

0
Roel Vlemmings

I numeri in virgola mobile possono solo rappresentano numeri che sono una somma di multipli negativi della base - per il punto in virgola mobile, naturalmente, che è due.

Esistono solo quattro frazioni decimali rappresentabili con precisione in virgola mobile binario: 0, 0,25, 0,5 e 0,75. Tutto il resto è un'approssimazione, nello stesso modo in cui 0.3333 ... è un'approssimazione per 1/3 nell'aritmetica decimale.

Il punto mobile è una buona scelta per i calcoli in cui la scala del risultato è l'importante. È una cattiva scelta in cui stai cercando di essere preciso con un numero di cifre decimali.

0
Mike Dimmick