Ruby BigDecimal 健全性检查(浮点 newb)

发布于 2024-09-05 05:47:17 字数 174 浏览 3 评论 0原文

我的理解是否正确,即使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

滿滿的愛 2024-09-12 05:47:17

使用浮点运算时有两个常见的陷阱。

第一个问题是Ruby浮点具有固定精度。实际上,这要么 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

在这种情况下,使用十进制浮点数仍然会产生舍入误差。

一些结论:

  • 如果您使用小数部分(例如金钱)进行计算,则十进制浮点数非常棒。
  • 如果您需要任意精度浮点,并且并不真正关心它们是十进制浮点还是二进制浮点,Ruby 的 BigDecimal 也可以很好地工作。
  • 如果您处理(科学)数据,您通常会处理固定精度的数字; Ruby 的内置浮动可能就足够了。
  • 您永远不能指望任何类型的浮点运算在所有情况下都是精确的。

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:

# float
1.0e+25 - 9999999999999999900000000.0
#=> 0.0

# bigdecimal
BigDecimal("1.0e+25") - BigDecimal("9999999999999999900000000.0")
#=> 100000000

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:

# float
(0.29 * 50).round
#=> 14  # not correct

# bigdecimal
(BigDecimal("0.29") * 50).round
#=> 15  # correct

A BigDecimal can describe decimal fractions precisely. However, there are fractions that cannot be described precisely with a decimal fraction either. For example 1/9 is an eternally-repeating decimal fraction (0.1111111111111...).

Again, this will bite you when you round a number. Consider:

# bigdecimal
(BigDecimal("1") / 9 * 9 / 2).round
#=> 0  # not correct

In this case, using decimal floating points will still give a rounding error.

Some conclusions:

  • Decimal floats are awesome if you do calculations with decimal fractions (money, for example).
  • Ruby's BigDecimal also works well if you need arbitrary precision floating points, and don't really care if they are decimal or binary floating points.
  • If you work with (scientific) data, you're typically dealing with fixed precision numbers; Ruby's built-in floats will probably suffice.
  • You can never expect arithmetic with any kind of floating point to be precise in all situations.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文