Float vs Decimal in ActiveRecord

A volte, i tipi di dati Activerecord mi confondono. Err, spesso. Una delle mie eterne domande è, per un caso determinato,

Dovrei usare :decimal o :float ?

Ho spesso incontrato questo link, ActiveRecord:: decimal vs: float? , ma le risposte non sono abbastanza chiare per essere sicuro:

Ho visto molti thread in cui le persone consigliano di non usare mai float e usano sempre i decimali. Ho anche visto alcuni suggerimenti per usare float solo per applicazioni scientifiche.

Ecco alcuni esempi di casi:

  • Geolocalizzazione / latitudine / longitudine: -45.756688 , 120.5777777 , …
  • Rapporto / percentuale: 0.9 , 1.25 , 1.333 , 1.4143 , …

Ho usato :decimal nel passato, ma ho trovato che trattare con oggetti BigDecimal in Ruby era inutilmente imbarazzante rispetto a un float. So anche che posso usare :integer ad esempio per rappresentare denaro / centesimi, ad esempio, ma non è adatto per altri casi, ad esempio quando le quantità in cui la precisione può cambiare nel tempo.

  • Quali sono i vantaggi / svantaggi dell’utilizzo di ciascuno?
  • Quali sarebbero alcune buone regole pratiche per sapere quale tipo usare?

Ricordo il mio professore CompSci che diceva di non usare mai i galleggianti per valuta.

Il motivo è che la specifica IEEE definisce i float in formato binario. Fondamentalmente, memorizza il segno, la frazione e l’esponente per rappresentare un Float. È come una notazione scientifica per binario (qualcosa come +1.43*10^2 ). Per questo motivo, è imansible memorizzare esattamente frazioni e decimali in Float.

Ecco perché c’è un formato decimale. Se lo fai:

 irb:001:0> "%.47f" % (1.0/10) => "0.10000000000000000555111512312578270211815834045" # not "0.1"! 

mentre se lo fai e basta

 irb:002:0> (1.0/10).to_s => "0.1" # the interprer rounds the number for you 

Quindi, se hai a che fare con piccole frazioni, come interessi composti o forse anche geolocalizzazione, ti consiglio caldamente il formato decimale, dal momento che nel formato decimale 1.0/10 è esattamente 0.1.

Tuttavia, va notato che, nonostante siano meno accurati, i float vengono elaborati più velocemente. Ecco un punto di riferimento:

 require "benchmark" require "bigdecimal" d = BigDecimal.new(3) f = Float(3) time_decimal = Benchmark.measure{ (1..10000000).each { |i| d * d } } time_float = Benchmark.measure{ (1..10000000).each { |i| f * f } } puts time_decimal #=> 6.770960 seconds puts time_float #=> 0.988070 seconds 

Risposta

Usa il float quando non ti interessa troppo la precisione. Ad esempio, alcune simulazioni e calcoli scientifici richiedono solo fino a 3 o 4 cifre significative. Questo è utile nel trading di precisione per la velocità. Poiché non hanno bisogno di precisione tanto quanto la velocità, utilizzerebbero il galleggiante.

Usa decimale se hai a che fare con numeri che devono essere precisi e riassumere per correggere il numero (come interessi di capitalizzazione e cose legate al denaro). Ricorda: se hai bisogno di precisione, dovresti sempre usare il decimale.

In Rails 3.2.18,: decimal si trasforma in: intero quando si usa SQLServer, ma funziona bene in SQLite. Passando a: float abbiamo risolto questo problema per noi.

La lezione appresa è “usa sempre database di sviluppo e distribuzione omogenei!”

In Rails 4.1.0, ho avuto problemi con il salvataggio di latitudine e longitudine nel database MySql. Non è ansible salvare un numero di frazione elevato con il tipo di dati float. E cambio il tipo di dati in decimale e lavoro per me.

   Difensore
     change_column: cities,: latitude,: decimal,: precision => 15,: scale => 13
     change_column: cities,: longitude,: decimal,: precision => 15,: scale => 13
   fine