Ruby BigDecimal 健全性检查(浮点 newb)
我的理解是否正确,即使用 Ruby BigDecimal
类型(即使具有不同的精度和标度长度)应该准确计算,还是应该预见浮点恶作剧?
我在 Rails 应用程序中的所有值都是 BigDecimal 类型,并且我看到一些错误(它们确实有不同的十进制长度),希望这只是我的方法而不是我的对象类型。
Is my understanding correct that with Ruby BigDecimal
types (even with varying precision and scale lengths) should calculate accurately or should I anticipate floating point shenanigans?
All my values within a Rails application are BigDecimal
type and I'm seeing some errors (they do have different decimal lengths), hoping it's just my methods and not my object types.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
使用浮点运算时有两个常见的陷阱。
第一个问题是Ruby浮点具有固定精度。实际上,这要么 1) 对您来说没有问题,要么 2) 灾难性的,或者 3) 介于两者之间。考虑以下情况:
精度差异为 1 亿!很严重,对吧?
只是精度误差仅为原始数字的0.000000000000001%左右。这是否是一个问题实际上取决于您。但使用 BigDecimal 可以解决这个问题,因为它具有任意精度。您唯一的限制是 Ruby 可用的内存。
第二个问题是浮点数无法准确表达所有分数。特别是,它们在处理十进制小数方面存在问题,因为 Ruby(以及大多数其他语言)中的浮点数是二进制浮点数。例如,十进制分数
0.2
是一个不断重复的二进制分数 (0.001100110011...
)。无论精度是多少,它永远无法准确地存储在二进制浮点中。当您对数字进行四舍五入时,这可能会产生很大的差异。考虑一下:
BigDecimal
可以精确地描述小数 分数。然而,有些分数也不能用小数精确描述。例如,1/9
是一个不断重复的小数分数 (0.1111111111111...
)。同样,当您对数字进行四舍五入时,这会困扰您。考虑:
在这种情况下,使用十进制浮点数仍然会产生舍入误差。
一些结论:
There are two common pitfalls when working with floating point arithmetic.
The first problem is that Ruby floating points have fixed precision. In practice this will either be 1) no problem for you or 2) disastrous, or 3) something in between. Consider the following:
A precision difference of 100 million! Pretty serious, right?
Except the precision error is only about 0.000000000000001% of the original number. It really is up to you to decide if this is a problem or not. But the problem is removed by using
BigDecimal
because it has arbitrary precision. Your only limit is memory available to Ruby.The second problem is that floating points cannot express all fractions accurately. In particular, they have problems with decimal fractions, because floats in Ruby (and most other languages) are binary floating points. For example, the decimal fraction
0.2
is an eternally-repeating binary fraction (0.001100110011...
). This can never be stored accurately in a binary floating point, no matter what the precision is.This can make a big difference when you're rounding numbers. Consider:
A
BigDecimal
can describe decimal fractions precisely. However, there are fractions that cannot be described precisely with a decimal fraction either. For example1/9
is an eternally-repeating decimal fraction (0.1111111111111...
).Again, this will bite you when you round a number. Consider:
In this case, using decimal floating points will still give a rounding error.
Some conclusions:
BigDecimal
also works well if you need arbitrary precision floating points, and don't really care if they are decimal or binary floating points.