ruby-on-rails rails - Flotante vs decimal en ActiveRecord





precision scale (4)


En Rails 4.1.0, he enfrentado un problema con el ahorro de latitud y longitud en la base de datos MySql. No se puede guardar un número de fracción grande con el tipo de datos flotante. Y cambio el tipo de datos a decimal y trabajando para mí.

  def change
    change_column :cities, :latitude, :decimal, :precision => 15, :scale => 13
    change_column :cities, :longitude, :decimal, :precision => 15, :scale => 13
  end

A veces, los tipos de datos de 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 para estar seguro:

He visto muchos hilos en los que la gente recomienda no usar nunca flotante y siempre usar decimales. También he visto sugerencias de algunas personas para usar el flotador solo para aplicaciones científicas.

Aquí hay algunos ejemplos de casos:

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

He usado :decimal en el pasado, pero encontré que tratar con objetos BigDecimal en Ruby era innecesariamente incómodo en comparación con un flotador. También sé que puedo usar :integer para representar dinero / centavos, por ejemplo, pero no es adecuado para otros casos, por ejemplo, cuando cantidades en las que la precisión podría cambiar con el tiempo.

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



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

La lección aprendida es "¡siempre use bases de datos homogéneas de desarrollo y despliegue!"




Recuerdo que mi profesor de CompSci me dijo que nunca usara flotadores como moneda.

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

Por eso hay un formato decimal. Si haces esto:

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

mientras que si solo haces

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

Entonces, si estás tratando con pequeñas fracciones, como intereses compuestos, o tal vez incluso con una geolocalización, recomendaría el formato decimal, ya que en formato decimal 1.0/10 es exactamente 0.1.

Sin embargo, debe tenerse en cuenta 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

Usa el flotador cuando no te importa 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 cambiar la precisión por velocidad. Ya que no necesitan precisión tanto como velocidad, usarían flotador.

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




+---------+----------------+---------+----------+---------------------------------------------+
| C#      | .Net Framework | Signed? | Bytes    | Possible Values                             |
| Type    | (System) type  |         | Occupied |                                             |
+---------+----------------+---------+----------+---------------------------------------------+
| sbyte   | System.Sbyte   | Yes     | 1        | -128 to 127                                 |
| short   | System.Int16   | Yes     | 2        | -32768 to 32767                             |
| int     | System.Int32   | Yes     | 4        | -2147483648 to 2147483647                   |
| long    | System.Int64   | Yes     | 8        | -9223372036854775808 to 9223372036854775807 |
| byte    | System.Byte    | No      | 1        | 0 to 255                                    |
| ushort  | System.Uint16  | No      | 2        | 0 to 65535                                  |
| uint    | System.UInt32  | No      | 4        | 0 to 4294967295                             |
| ulong   | System.Uint64  | No      | 8        | 0 to 18446744073709551615                   |
| float   | System.Single  | Yes     | 4        | Approximately ±1.5 x 10-45 to ±3.4 x 1038   |
|         |                |         |          |  with 7 significant figures                 |
| double  | System.Double  | Yes     | 8        | Approximately ±5.0 x 10-324 to ±1.7 x 10308 |
|         |                |         |          |  with 15 or 16 significant figures          |
| decimal | System.Decimal | Yes     | 12       | Approximately ±1.0 x 10-28 to ±7.9 x 1028   |
|         |                |         |          |  with 28 or 29 significant figures          |
| char    | System.Char    | N/A     | 2        | Any Unicode character (16 bit)              |
| bool    | System.Boolean | N/A     | 1 / 2    | true or false                               |
+---------+----------------+---------+----------+---------------------------------------------+

Para más información, ver:
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/921a8ffc-9829-4145-bdc9-a96c1ec174a5





ruby-on-rails types floating-point decimal rails-activerecord