Ruby BigDecimal 健全性检查(浮点 newb) [英] Ruby BigDecimal sanity check (floating point newb)

查看:47
本文介绍了Ruby BigDecimal 健全性检查(浮点 newb)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的理解是否正确,即使用 Ruby 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?

我在 Rails 应用程序中的所有值都是 BigDecimal 类型,我看到一些错误(它们确实有不同的十进制长度),希望这只是我的方法而不是我的对象类型.

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.

推荐答案

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

There are two common pitfalls when working with floating point arithmetic.

第一个问题是Ruby浮点有固定的精度.在实践中,这要么是 1) 对您没有问题,要么是 2) 灾难性的,或者 3) 介于两者之间.考虑以下几点:

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?

除了精度误差只有原始数字的0.000000000000001%左右.这真的是由你来决定这是否是一个问题.但是使用 BigDecimal 可以解决问题,因为它具有任意精度.您唯一的限制是 Ruby 可用的内存.

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.

第二个问题是浮点数不能准确表达所有分数.特别是,它们在 decimal 分数方面存在问题,因为 Ruby(和大多数其他语言)中的浮点数是 binary 浮点数.例如,十进制分数 0.2 是一个永远重复的二进制分数 (0.001100110011...).无论精度如何,这永远无法准确存储在二进制浮点中.

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

BigDecimal 可以精确地描述 decimal 分数.但是,也有无法用小数精确描述的分数.例如 1/9 是一个永远重复的小数部分 (0.1111111111111...).

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.

一些结论:

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

这篇关于Ruby BigDecimal 健全性检查(浮点 newb)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆