Ruby-on-rails ActiveRecord 中的浮点数与十进制数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8514167/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 02:30:07  来源:igfitidea点击:

Float vs Decimal in ActiveRecord

ruby-on-railstypesfloating-pointdecimalrails-activerecord

提问by Jonathan Allard

Sometimes, Activerecord data types confuse me. Err, often. One of my eternal questions is, for a given case,

有时,Activerecord 数据类型让我感到困惑。呃,经常。我永恒的问题之一是,对于给定的案例,

Should I use :decimalor :float?

我应该使用:decimal还是:float

I've often come across this link, ActiveRecord: :decimal vs :float?, but the answers aren't quite clear enough for me to be certain:

我经常遇到这个链接,ActiveRecord::decimal vs :float? ,但答案还不够清楚,我无法确定:

I've seen many threads where people recommend flat out to never use float and always use decimal. I've also seen suggestions by some people to use float for scientific applications only.

我见过很多线程,其中人们建议完全不要使用浮点数而始终使用小数。我还看到一些人建议仅将浮动用于科学应用。

Here are some example cases:

以下是一些示例案例:

  • Geolocation/latitude/longitude: -45.756688, 120.5777777, ...
  • Ratio/percentage: 0.9, 1.25, 1.333, 1.4143, ...
  • 地理位置/纬度/经度:-45.756688, 120.5777777, ...
  • 比率/百分比:0.9, 1.25, 1.333, 1.4143, ...

I have used :decimalin the past, but I found dealing with BigDecimalobjects in Ruby was unnecessarily awkward as compared to a float. I also know I can use :integerto represent money/cents, for example, but it doesn't quite fit for other cases, for example when quantities in which precision could change over time.

:decimal过去曾经使用过,但我发现与BigDecimal浮点数相比,在 Ruby 中处理对象是不必要的尴尬。我也知道我可以:integer用来表示货币/美分,例如,但它不太适合其他情况,例如当精度可能随时间变化的数量时。

  • What are the advantages/disadvantages of using each?
  • What would be some good rules of thumb to know which type to use?
  • 使用每个的优点/缺点是什么?
  • 知道使用哪种类型的一些好的经验法则是什么?

回答by Iuri G.

I remember my CompSci professor saying never to use floats for currency.

我记得我的 CompSci 教授说过永远不要使用浮动货币。

The reason for that is how the IEEE specification defines floatsin binary format. Basically, it stores sign, fraction and exponent to represent a Float. It's like a scientific notation for binary (something like +1.43*10^2). Because of that, it is impossible to store fractions and decimals in Float exactly.

原因在于IEEE 规范如何以二进制格式定义浮点数。基本上,它存储符号、分数和指数来表示浮点数。它就像二进制的科学记数法(类似于+1.43*10^2)。因此,不可能在 Float 中准确存储分数和小数。

That's why there is a Decimal format. If you do this:

这就是为什么有十进制格式的原因。如果你这样做:

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

whereas if you just do

而如果你只是这样做

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

So if you are dealing with small fractions, like compounding interests, or maybe even geolocation, I would highly recommend Decimal format, since in decimal format 1.0/10is exactly 0.1.

因此,如果您正在处理小部分,例如复利,甚至地理定位,我强烈推荐十进制格式,因为十进制格式1.0/10正好是 0.1。

However, it should be noted that despite being less accurate, floats are processed faster. Here's a 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

Answer

回答

Use floatwhen you don't care about precision too much. For example, some scientific simulations and calculations only need up to 3 or 4 significant digits. This is useful in trading off accuracy for speed. Since they don't need precision as much as speed, they would use float.

当您不太在意精度时使用浮点数。例如,一些科学模拟和计算最多只需要 3 或 4 位有效数字。这在权衡准确性和速度方面很有用。因为他们不需要像速度一样的精度,所以他们会使用浮点数。

Use decimalif you are dealing with numbers that need to be precise and sum up to correct number (like compounding interests and money-related things). Remember: if you need precision, then you should always use decimal.

如果您处理的数字需要精确并求和为正确的数字(如复利和与金钱相关的事物),请使用小数。请记住:如果您需要精度,那么您应该始终使用十进制。

回答by ryan0

In Rails 3.2.18, :decimal turns into :integer when using SQLServer, but it works fine in SQLite. Switching to :float solved this issue for us.

在 Rails 3.2.18 中,:decimal 在使用 SQLServer 时变成了 :integer,但它在 SQLite 中工作正常。切换到 :float 为我们解决了这个问题。

The lesson learned is "always use homogeneous development and deployment databases!"

吸取的教训是“始终使用同构开发和部署数据库!”

回答by Rokibul Hasan

In Rails 4.1.0, I have faced problem with saving latitude and longitude to MySql database. It can't save large fraction number with float data type. And I change the data type to decimal and working for me.

在 Rails 4.1.0 中,我遇到了将纬度和经度保存到 MySql 数据库的问题。它不能用浮点数据类型保存大分数。我将数据类型更改为十进制并对我来说有效。

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