[ruby-on-rails] ActiveRecord의 부동 대 소수

때로는 Activerecord 데이터 형식이 혼란 스럽습니다. 자 주요 내 영원한 질문 중 하나는 주어진 경우에

:decimal또는 사용해야합니까 :float?

나는 종종이 링크, ActiveRecord :: decimal vs : float? 그러나 대답은 확실하지 않습니다.

사람들이 float을 사용하지 않고 항상 10 진수를 사용하도록 플랫 아웃을 권장하는 많은 스레드를 보았습니다. 또한 일부 사람들은 과학 응용 프로그램에만 float를 사용하라는 제안을 보았습니다.

다음은 몇 가지 사례입니다.

  • 위치 정보 / 위도 / 경도 : -45.756688, 120.5777777, …
  • 비율 / 비율 : 0.9, 1.25, 1.333, 1.4143, …

나는 :decimal과거에 사용했지만 BigDecimalRuby에서 객체를 다루는 것이 플로트에 비해 불필요하게 어색 하다는 것을 알았습니다 . :integer예를 들어 돈 / 센트를 나타내는 데 사용할 수도 있지만 시간이 지남에 따라 정밀도가 변할 수있는 다른 경우에는 적합하지 않습니다.

  • 각각을 사용할 때의 장점 / 단점은 무엇입니까?
  • 어떤 유형을 사용해야하는지 아는 좋은 경험 법은 무엇입니까?


답변

CompSci 교수는 통화에 플로트를 사용하지 말라고 말합니다.

그 이유는 IEEE 사양 이 이진 형식으로 부동 소수점정의 하는 방법 때문입니다 . 기본적으로 Float를 나타내는 부호, 분수 및 지수를 저장합니다. 이진에 대한 과학적 표기법과 같습니다 (같은 것 +1.43*10^2). 이 때문에 분수와 소수를 Float에 정확하게 저장하는 것은 불가능합니다.

그렇기 때문에 십진법 형식이 있습니다. 이렇게하면 :

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

반면에 당신이 방금한다면

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

따라서 복리 관심사 또는 지리적 위치와 같은 작은 분수를 처리하는 경우 십진 형식 1.0/10은 정확히 0.1 이므로 십진 형식을 사용하는 것이 좋습니다 .

그러나 정확도는 떨어지지 만 플로트는 더 빠르게 처리됩니다. 벤치 마크는 다음과 같습니다.

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

대답

정밀도를 너무 신경 쓰지 않으면 float를 사용하십시오 . 예를 들어, 일부 과학적 시뮬레이션 및 계산에는 최대 3 자리 또는 4 자리의 유효 숫자 만 필요합니다. 속도의 정확도를 떨어 뜨리는 데 유용합니다. 속도만큼 정밀도가 필요하지 않으므로 float를 사용합니다.

정확한 숫자가 필요한 숫자를 다룰 경우 십진수를 사용하십시오 . 기억하십시오 : 정밀도가 필요한 경우 항상 10 진수를 사용해야합니다.


답변

Rails 3.2.18에서 : decimal은 SQLServer를 사용할 때 : integer로 바뀌지 만 SQLite에서는 잘 작동합니다. : float로 전환하면이 문제가 해결되었습니다.

배운 교훈은 “항상 균질 한 개발 및 배포 데이터베이스를 사용하는 것”입니다.


답변

Rails 4.1.0에서 위도 및 경도를 MySql 데이터베이스에 저장하는 데 문제가 있습니다. float 데이터 형식으로 큰 분수를 저장할 수 없습니다. 그리고 데이터 유형을 10 진수로 변경하고 나를 위해 일합니다.

  데프 변경
    change_column : 도시, : 위도, : 10 진수, : 정밀도 => 15, : 스케일 => 13
    change_column : 도시, : 경도, : 10 진수, : 정밀도 => 15, : 스케일 => 13
  종료


답변