webentwicklung-frage-antwort-db.com.de

Float vs Decimal in ActiveRecord

Manchmal verwirren mich Activerecord-Datentypen. Ähm, oft. Eine meiner ewigen Fragen ist für einen bestimmten Fall,

Sollte ich es benutzen :decimal oder :float?

Ich bin oft auf diesen Link gestoßen, ActiveRecord:: decimal vs: float?, aber die Antworten sind nicht ganz klar genug für mich, um sicher zu sein:

Ich habe viele Threads gesehen, in denen Leute empfehlen, niemals float und immer decimal zu verwenden. Ich habe auch Vorschläge von einigen Leuten gesehen, Float nur für wissenschaftliche Anwendungen zu verwenden.

Hier sind einige Beispielfälle:

  • Geolocation/Breite/Länge: -45.756688, 120.5777777, ...
  • Verhältnis/Prozentsatz: 0.9, 1.25, 1.333, 1.4143, ...

Ich habe benutzt :decimal in der Vergangenheit, aber ich fand den Umgang mit BigDecimal Objekten in Ruby war im Vergleich zu einem Float unnötig umständlich. Ich weiß auch, dass ich :integer um zum Beispiel Geld/Cent darzustellen, aber es passt nicht für andere Fälle, zum Beispiel wenn sich die Genauigkeit im Laufe der Zeit ändern könnte.

  • Was sind die Vor- und Nachteile der jeweiligen Verwendung?
  • Was wären gute Faustregeln, um zu wissen, welcher Typ verwendet werden soll?
269
Jonathan Allard

Ich erinnere mich, dass mein CompSci-Professor sagte, er solle niemals Floats als Währung verwenden.

Der Grund dafür ist, wie die IEEE-Spezifikation Floats definiert im Binärformat. Grundsätzlich werden Vorzeichen, Bruch und Exponent gespeichert, um einen Float darzustellen. Es ist wie eine wissenschaftliche Notation für binär (so etwas wie +1.43*10^2). Aus diesem Grund ist es nicht möglich, Brüche und Dezimalstellen exakt in Float zu speichern.

Deshalb gibt es ein Dezimalformat. Wenn du das tust:

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

wenn Sie es einfach tun

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

Wenn Sie es also mit kleinen Brüchen wie Zinseszinsen oder sogar Geolokalisierung zu tun haben, würde ich das Dezimalformat sehr empfehlen, da das Dezimalformat 1.0/10 ist genau 0.1.

Es ist jedoch zu beachten, dass Floats trotz ihrer geringeren Genauigkeit schneller verarbeitet werden. Hier ist ein Benchmark:

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

Antworten

Verwenden Sie float , wenn Sie nicht zu sehr auf Präzision achten. Beispielsweise benötigen einige wissenschaftliche Simulationen und Berechnungen nur bis zu 3 oder 4 signifikante Stellen. Dies ist nützlich, um die Genauigkeit gegen die Geschwindigkeit auszutauschen. Da sie weniger Präzision als Geschwindigkeit benötigen, würden sie Float verwenden.

Verwenden Sie Dezimal , wenn Sie es mit Zahlen zu tun haben, die präzise sein und die richtige Zahl ergeben müssen (wie Zinseszinsen und geldbezogene Dinge). Denken Sie daran: Wenn Sie Genauigkeit benötigen, sollten Sie immer eine Dezimalzahl verwenden.

404
Iuri G.

In Rails 3.2.18 verwandelt sich: decimal in: integer, wenn SQLServer verwendet wird. In SQLite funktioniert dies jedoch einwandfrei. Der Wechsel zu: float hat dieses Problem für uns gelöst.

Die Lektion lautet: "Verwenden Sie immer homogene Entwicklungs- und Bereitstellungsdatenbanken!"

18
ryan0

In Rails 4.1.0 habe ich Probleme mit dem Speichern von Breiten- und Längengraden in der MySql-Datenbank. Es kann keine große Bruchzahl mit dem Datentyp float gespeichert werden. Und ich ändere den Datentyp auf dezimal und für mich arbeiten.

 def change 
 change_column: cities,: width,: decimal,: precision => 15,: scale => 13 
 change_column: cities,: longitude,: decimal,: precision => 15,: scale => 13 
 End 
11
Rokibul Hasan