Float vs Decimal dans ActiveRecord

Parfois, les types de données Activerecord m’embrouillent. Err, souvent. Une de mes questions éternelles est, pour un cas donné,

Devrais-je utiliser :decimal ou :float ?

J’ai souvent rencontré ce lien, ActiveRecord:: décimal vs: float? , mais les réponses ne sont pas assez claires pour que je sois certain:

J’ai vu beaucoup de threads où les gens recommandent de ne jamais utiliser float et d’utiliser décimal. J’ai également vu des suggestions de certaines personnes d’utiliser float uniquement pour des applications scientifiques.

Voici quelques exemples de cas:

  • Géolocalisation / latitude / longitude: -45.756688 , 120.5777777 , …
  • Ratio / pourcentage: 0.9 , 1.25 , 1.4143 , 1.4143 , …

J’ai utilisé :decimal dans le passé, mais j’ai trouvé que traiter des objects BigDecimal dans Ruby était inutilement gênant par rapport à un float. Je sais aussi que je peux utiliser :integer pour représenter de l’argent / cents, par exemple, mais cela ne convient pas à d’autres cas, par exemple lorsque des quantités dans lesquelles la précision peut changer avec le temps.

  • Quels sont les avantages / inconvénients de l’utilisation de chacun?
  • Quelles seraient les bonnes règles pour savoir quel type utiliser?

    Je me souviens que mon professeur CompSci disait de ne jamais utiliser de flotteurs pour la monnaie.

    La raison en est que la spécification IEEE définit des flottants au format binary. Fondamentalement, il stocke signe, fraction et exposant pour représenter un flotteur. C’est comme une notation scientifique pour le binary (quelque chose comme +1.43*10^2 ). À cause de cela, il est impossible de stocker des fractions et des décimales exactement dans Float.

    C’est pourquoi il existe un format décimal. Si tu fais ça:

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

    alors que si tu fais juste

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

    Donc, si vous avez affaire à de petites fractions, comme les intérêts de composition, ou même la géolocalisation, je recommande fortement le format décimal, car au format décimal 1.0/10 correspond exactement à 0.1.

    Cependant, il convient de noter que, même si elles sont moins précises, les flottants sont traités plus rapidement. Voici une référence:

     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 

    Répondre

    Utilisez float quand vous ne vous souciez pas trop de la précision. Par exemple, certaines simulations et calculs scientifiques ne nécessitent que 3 ou 4 chiffres significatifs. Ceci est utile pour échanger la précision contre la vitesse. Comme ils n’ont pas besoin de précision autant que la vitesse, ils utiliseraient le flottant.

    Utilisez le nombre décimal si vous avez affaire à des nombres qui doivent être précis et résumer pour corriger le nombre (comme les intérêts composés et les éléments liés à l’argent). Rappelez-vous: si vous avez besoin de précision, vous devez toujours utiliser décimal.

    Dans Rails 3.2.18,: decimal se transforme en: entier lorsque SQLServer est utilisé, mais il fonctionne correctement dans SQLite. Passer à: float a résolu ce problème pour nous.

    La leçon apprise est “toujours utiliser des bases de données de développement et de déploiement homogènes!”

    Dans Rails 4.1.0, j’ai rencontré des problèmes avec la sauvegarde de la latitude et de la longitude dans la firebase database MySql. Il ne peut pas enregistrer un grand nombre de fractions avec un type de données flottant. Et je change le type de données en décimal et travaille pour moi.

       déf changement
         change_column: cities,: latitude,: decimal,: precision => 15,: scale => 13
         change_column: cities,: longitude,: decimal,: precision => 15,: scale => 13
       fin