Quando utilizzare float vs decimale


14

Sto creando questa API e il database memorizzerà i valori che rappresentano uno dei seguenti:

  • percentuale
  • media
  • Vota

Onestamente non ho idea di come rappresentare qualcosa che l'intervallo è compreso tra 0 e 100% in numeri. Dovrebbe essere

  • 0,00 - 1,00
  • 0,00 - 100,00
  • qualsiasi altra alternativa che non conosco

C'è una scelta chiara per quello? Un modo globale di rappresentare nei database qualcosa che va dallo 0 al 100%? Andando oltre, qual è il tipo corretto per esso, float o decimale?

Grazie.



5
I numeri possono essere memorizzati in molti modi. Non c'è nulla di intrinsecamente sbagliato nel memorizzare una percentuale usando 0-100 o usando 0-1. Ciò che conta è cosa devi fare con i numeri, quale precisione hai bisogno e così via. Devi spiegare più contesto prima di dare una buona risposta. Hai bisogno di memorizzare numeri che sono esattamente rappresentabili con un piccolo numero di cifre decimali? Se fai le cose nella media, ottieni frazioni come terzi o settimi. Devi memorizzarli esattamente? O solo approssimativamente? Quanto approssimativamente? Cosa farai con loro?
Eric Postpischil,

1
Se i valori sono compresi tra 0,00 e 100,00 con incrementi di 0,01, questo significa 10001 valori diversi. Basta usare un intper rappresentare i centesimi o in unità di Permiria o ‱.
chux - Ripristina Monica il

@ chux-ReinstateMonica - Sì, sono possibili "numeri interi ridimensionati", ma goffi.
Rick James,

@RickJames Forse. Non ho trovato interi scalati difficili.
chux - Ripristina Monica il

Risposte:


4

Prenderò la posizione opposta.

FLOATè per numeri approssimativi, come percentuali, medie, ecc. Dovresti eseguire la formattazione mentre visualizzi i valori, nel codice dell'app o usando la FORMAT()funzione di MySQL.

Non testare mai float_value = 1.3; ci sono molte ragioni per cui ciò fallirà.

DECIMALdovrebbe essere usato per valori monetari. DECIMALevita un secondo arrotondamento quando un valore deve essere arrotondato a dollari / centesimi / euro / ecc. Ai contabili non piacciono le frazioni di centesimi.

L'implementazione di MySQL di DECIMALconsente 65 cifre significative; FLOATdà circa 7 e DOUBLEcirca 16. 7 è di solito più che sufficiente per sensori e calcoli scientifici.

Per quanto riguarda "percentuale" - A volte l'ho usato TINYINT UNSIGNEDquando volevo consumare solo 1 byte di memoria e non ho bisogno di molta precisione; a volte l'ho usato FLOAT(4 byte). Non esiste un tipo di dati ottimizzato appositamente per la percentuale. (Nota anche che DECIMAL(2,0)non può contenere il valore 100, quindi tecnicamente ne avresti bisogno DECIMAL(3,0).)

O a volte ho usato un FLOATvalore che conteneva un valore compreso tra 0 e 1. Ma poi avrei bisogno di assicurarmi di moltiplicare per 100 prima di visualizzare la "percentuale".

Di Più

Tutti e tre di "percentuale, media, tasso" odorano di galleggianti, quindi sarebbe la mia prima scelta.

Un criterio per decidere il tipo di dati ... Quante copie del valore esistono?

Se hai una tabella da un miliardo di righe con una colonna per una percentuale, consideralo TINYINT occorrerebbe 1 byte (1 GB in totale), ma FLOATrichiederebbe 4 byte (4 GB in totale). OTOH, la maggior parte delle applicazioni non ha tante righe, quindi potrebbe non essere rilevante.

Come regola 'generale', i valori "esatti" dovrebbero usare una qualche forma di INTo DECIMAL. Le cose inesatte (calcoli scientifici, radici quadrate, divisione, ecc.) Dovrebbero usareFLOAT (o DOUBLE).

Inoltre, il formattazione dell'output dovrebbe di solito essere lasciata al front-end dell'applicazione. Cioè, anche se una "media" può essere calcolata su "14.6666666 ...", il display dovrebbe mostrare qualcosa come "14.7"; questo è più amichevole per gli umani. Nel frattempo, hai il valore sottostante per decidere in seguito che "15" o "14.667" è la formattazione di output preferibile.

L'intervallo "0,00 - 100,00" può essere eseguito con FLOAT e utilizzare la formattazione dell'output o con DECIMAL(5,2)(3 byte) con la predeterminazione che si desidera sempre la precisione indicata .


3

Consiglierei generalmente di non utilizzare float. I numeri in virgola mobile rappresentano i numeri in base-2, il che fa sì che alcuni numeri (esatti) vengano arrotondati per eccesso in operazioni o confronti, poiché non possono essere memorizzati con precisione in base-2. Ciò può portare a comportamenti sorprendenti.

Prendere in considerazione il seguente esempio :

create table t (num float);
insert into t values(1.3);

select * from t;

| num |
| --: |
| 1.3 |

select * from t where num = 1.3;

| num |
| --: |

Il confronto base-2 del numero 1.3fallisce. Questo è difficile.

In confronto, i decimali forniscono una rappresentazione accurata dei numeri finiti all'interno del loro intervallo. Se si floatpassa decimal(2, 1)all'esempio sopra, si ottengono i risultati previsti.


4
Questa risposta è falsa sotto diversi aspetti. "In confronto, i decimali hanno un intervallo più piccolo ma forniscono un'esatta rappresentazione di numeri finiti all'interno di quell'intervallo" è falso: il decimale non rappresenta ⅓ esattamente. "Alcuni numeri (esatti, finiti) sono arrotondati per eccesso" non è corretto; i numeri non sono "arrotondati per eccesso". Le conversioni e altre operazioni possono arrotondare. La modalità di arrotondamento predefinita è più comunemente arrotondata al più vicino-pareggio-pari, non arrotondata per eccesso.
Eric Postpischil,

4
I problemi con precisione non sono dovuti a "numeri in virgola mobile" ma semplicemente a rappresentazioni numeriche: tutte le rappresentazioni numeriche finite hanno una precisione limitata: virgola mobile, punto fisso, numero intero, razionale, decimale, binario, tutto.
Eric Postpischil,

2
Sospiro. Che cosa hai riparato? Il mio commento dice che la risposta è sbagliata perché dice che il decimale fornisce una rappresentazione esatta dei numeri nel suo intervallo, ma in realtà non lo fa perché non fornisce una rappresentazione esatta di ⅓. Il cambiamento dice "accurato" invece di "esatto", ma allora perché il virgola mobile binario non è altrettanto buono - nessuno dei due è esatto per ⅓, e entrambi o nessuno dei due è accurato, a seconda di quale sia la soglia per l'accuratezza e quanta precisione loro hanno. La domanda indica che le medie saranno rappresentate e la media di tre cose ti dà numeri come ⅓.
Eric Postpischil,

4
Il commento dice che il più vicino a legami più vicini è usato più comunemente, ma la risposta dice ancora arrotondamento. La risposta dice che i confronti possono arrotondare, ma i confronti sono perfetti: i confronti restituiscono sempre un risultato matematicamente corretto, senza arrotondamenti. (Alcuni linguaggi di programmazione possono convertire gli operandi prima del confronto, ma quelli sono operazioni separate.)
Eric Postpischil,

1
1/3 non può essere rappresentato esattamente in binario o decimale. Uno sconto del 20% su $ 14,99 richiederà l'arrotondamento di centesimi frazionari non esiste.
Rick James,

0

La differenza tra float e decimale è la precisione. Il decimale può rappresentare con precisione al 100% qualsiasi numero all'interno della precisione del formato decimale, mentre Float non può rappresentare con precisione tutti i numeri.

Utilizzare Decimale per es. Valore relativo finanziario e usare float per es. Valore relativo grafico


0

Ti consiglio di usarlo decimal(5,2)se lo memorizzi nello stesso modo in cui lo visualizzerai poiché decimalè per preservare l'esatta precisione. (Vedi https://dev.mysql.com/doc/refman/8.0/en/fixed-point-types.html )

Poiché i valori in virgola mobile sono approssimativi e non memorizzati come valori esatti, i tentativi di trattarli come esatti nei confronti possono causare problemi. Sono inoltre soggetti a dipendenze dalla piattaforma o dall'implementazione.

( https://dev.mysql.com/doc/refman/8.0/en/floating-point-types.html )

Un valore in virgola mobile come scritto in un'istruzione SQL potrebbe non essere uguale al valore rappresentato internamente.

Per le colonne DECIMAL, MySQL esegue le operazioni con una precisione di 65 cifre decimali, che dovrebbe risolvere i problemi di imprecisione più comuni.

https://dev.mysql.com/doc/refman/8.0/en/problems-with-float.html


0

Decimale: nel caso di applicazioni finanziarie è meglio usare i tipi decimali perché offre un alto livello di accuratezza e facile da evitare errori di arrotondamento

Doppio: i tipi doppi sono probabilmente il tipo di dati più comunemente usato per valori reali, ad eccezione della gestione del denaro.

Galleggiante: viene utilizzato principalmente nelle librerie grafiche perché richieste molto elevate per le capacità di elaborazione, utilizzate anche situazioni che possono sopportare errori di arrotondamento.

Riferimento: http://net-informations.com/q/faq/float.html


0
mysql> create table numbers (a decimal(10,2), b float);
mysql> insert into numbers values (100, 100);
mysql> select @a := (a/3), @b := (b/3), @a * 3, @b * 3 from numbers \G

*********************************************************************

@a := (a/3): 33.333333333
@b := (b/3): 33.333333333333
@a + @a + @a: 99.999999999000000000000000000000
@b + @b + @b: 100

Il decimale ha fatto esattamente quello che dovrebbe fare in questi casi, ha troncato il resto, perdendo così la parte 1/3.

Quindi per le somme, il decimale è migliore, ma per le divisioni il float è migliore, fino a un certo punto, ovviamente. Voglio dire, l'uso di DECIMAL non ti darà "aritmetica a prova di errore" in alcun modo.

Spero che questo possa aiutare.


0

In tsql: Float, 0.0 memorizza come 0 e non è necessario definire dopo la cifra dei punti decimali, ad esempio non è necessario scrivere Float (4,2). Decimale, 0,0 memorizza come 0,0 e ha un'opzione per definire come decimale (4,2), suggerirei 0,00-1,00, facendo questo puoi calcolare il valore di quella percentuale senza moltiplicare per 100 e se riferisci quindi imposta il tipo di dati di quella colonna in percentuale come MS Excel e altre piattaforme simili 0.5 -> 50%.

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.