Flotante vs Decimal en ActiveRecord

A veces, los tipos de datos Activerecord me confunden. Err, a menudo. Una de mis preguntas eternas es, para un caso dado,

¿Debo usar :decimal o :float ?

A menudo he encontrado este enlace, ActiveRecord:: decimal vs: float? , pero las respuestas no son lo suficientemente claras como para estar seguro:

He visto muchos hilos en los que la gente lo recomienda para que nunca use flotadores y siempre use decimales. También he visto sugerencias de algunas personas de usar float solo para aplicaciones científicas.

Aquí hay algunos ejemplos de casos:

  • Geolocalización / latitud / longitud: -45.756688 , 120.5777777 , …
  • Ratio / porcentaje: 0.9 , 1.25 , 1.333 , 1.4143 , …

He usado :decimal en el pasado, pero encontré que lidiar con objetos BigDecimal en Ruby era innecesariamente incómodo en comparación con un flotante. También sé que puedo usar :integer para representar dinero / centavos, por ejemplo, pero no encaja para otros casos, por ejemplo, cuando hay cantidades en las que la precisión puede cambiar con el tiempo.

  • ¿Cuáles son las ventajas / desventajas de usar cada uno?
  • ¿Cuáles serían algunas buenas reglas generales para saber qué tipo usar?

Recuerdo a mi profesor de CompSci diciendo que nunca usas carrozas para moneda.

La razón de esto es cómo la especificación IEEE define flotantes en formato binario. Básicamente, almacena el signo, la fracción y el exponente para representar un Float. Es como una notación científica para binario (algo así como +1.43*10^2 ). Debido a eso, es imposible almacenar fracciones y decimales en Float exactamente.

Es por eso que hay un formato Decimal. Si haces esto:

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

mientras que si lo haces

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

Entonces, si se trata de fracciones pequeñas, como intereses compuestos, o incluso geolocalización, recomiendo el formato Decimal, ya que en formato decimal 1.0/10 es exactamente 0.1.

Sin embargo, cabe señalar que, a pesar de ser menos precisos, los flotadores se procesan más rápido. Aquí hay un punto de referencia:

 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 

Responder

Use flotador cuando no le importe demasiado la precisión. Por ejemplo, algunas simulaciones y cálculos científicos solo necesitan hasta 3 o 4 dígitos significativos. Esto es útil para compensar la precisión de la velocidad. Como no necesitan precisión tanto como la velocidad, usarán flotador.

Use decimal si está tratando con números que deben ser precisos y resum el número correcto (como intereses compuestos y cosas relacionadas con el dinero). Recuerde: si necesita precisión, siempre debe usar decimal.

En Rails 3.2.18,: decimal se convierte en: entero cuando se usa SQLServer, pero funciona bien en SQLite. Cambiar a: flotador resolvió este problema para nosotros.

La lección aprendida es “¡utilice siempre bases de datos de desarrollo e implementación homogéneas!”

En Rails 4.1.0, he enfrentado un problema al guardar la latitud y la longitud de la base de datos MySql. No puede guardar un número grande de fracciones con el tipo de datos float. Y cambio el tipo de datos a decimal y estoy trabajando para mí.

   def cambio
     change_column: cities,: latitude,: decimal,: precision => 15,: scale => 13
     change_column: cities,: longitude,: decimal,: precision => 15,: scale => 13
   fin