Ruby BigDecimal
유형 (정밀도와 스케일의 길이가 다를지라도)을 정확하게 계산해야하는지 또는 부동 소수점 헛수고를 예상해야합니까?Ruby BigDecimal 온 전성 체크 (부동 소수점 newb)
레일 애플리케이션의 모든 내 값은 BigDecimal
이며 일부 오류가 발생합니다 (길이가 다릅니다). 내 메소드가 아니라 객체 유형이되기를 바랍니다.
Ruby BigDecimal
유형 (정밀도와 스케일의 길이가 다를지라도)을 정확하게 계산해야하는지 또는 부동 소수점 헛수고를 예상해야합니까?Ruby BigDecimal 온 전성 체크 (부동 소수점 newb)
레일 애플리케이션의 모든 내 값은 BigDecimal
이며 일부 오류가 발생합니다 (길이가 다릅니다). 내 메소드가 아니라 객체 유형이되기를 바랍니다.
부동 소수점 연산으로 작업 할 때 두 가지 일반적인 함정이 있습니다.
첫번째 문제점은 루비 부동 소수점이 고정 된 정밀도를가집니다. 실제로 이것은 1) 너에게 아무런 문제가 없거나 2) 비참한 것, 3) 사이에있는 것 중 하나 다. 다음을 고려하십시오.
# float
1.0e+25 - 9999999999999999900000000.0
#=> 0.0
# bigdecimal
BigDecimal("1.0e+25") - BigDecimal("9999999999999999900000000.0")
#=> 100000000
정밀도 차이는 1 억입니다! 아주 심각 하죠?
정밀도 오류는 원래 숫자의 약 0.000000000000001 %입니다. 이것이 문제가되는지 아닌지를 결정하는 것은 당신에게 달려 있습니다. 그러나 임의의 정밀도를 가지기 때문에 BigDecimal
을 사용하면 문제가 해결됩니다. 유일한 제한은 Ruby에서 사용할 수있는 메모리입니다.
두 번째 문제은 부동 소수점이 모든 분수를 정확하게 표현할 수 없다는 점입니다. 특히 그들은 십진수 부분에 문제가 있습니다. Ruby (및 대부분의 다른 언어)의 부동 소수점은 이진 부동 소수점이기 때문입니다. 예를 들어, 십진수 소수 0.2
은 영원 반복 이진 소수 (0.001100110011...
)입니다. 정밀도가 무엇이든 이진 부동 소수점에 정확하게 저장할 수 없습니다.
숫자를 반올림하는 경우 큰 차이가 발생할 수 있습니다. 고려 :
# float
(0.29 * 50).round
#=> 14 # not correct
# bigdecimal
(BigDecimal("0.29") * 50).round
#=> 15 # correct
BigDecimal
정확하게 진수 분수를 설명 할 수 있습니다. 그러나 십진수로도 정확하게 기술 할 수없는 분수가 있습니다. 예를 들어, 1/9
은 영원히 반복되는 소수 부분입니다 (0.1111111111111...
).
다시 말하지만, 번호를 반올림하면이 문제가 발생합니다. 고려 :
# bigdecimal
(BigDecimal("1")/9 * 9/2).round
#=> 0 # not correct
를이 경우, 여전히는 반올림 오류를 줄 것이다 소수점 부동 포인트를 사용하여.
어떤 결론 : 당신이 (예를 들어, 돈) 소수 분수 계산을 할 경우
BigDecimal
은 임의의 정밀도 부동 소수점이 필요하고 10 진수 또는 2 진 부동 소수점인지 상관하지 않습니다.
"실제로이 문제는 1) 문제가되지 않거나 2) 비참한 것, 3) 중간에있는 것 중 하나입니다." –