【问题标题】:Why is BigDecimal more precise than double?为什么 BigDecimal 比 double 更精确?
【发布时间】:2013-06-17 01:37:37
【问题描述】:

我想知道BigDecimaldouble 之间的确切区别。我知道BigDecimaldouble 更精确,您应该使用前者进行计算。

为什么更精确?为什么不能自定义double 使其像BigDecimal 一样工作?或者用double计算有什么好处?

【问题讨论】:

标签: java double bigdecimal


【解决方案1】:

BigDecimal

不可变的、任意精度的有符号十进制数。 BigDecimal 由一个任意精度的整数未缩放值和一个 32 位整数刻度组成。如果为零或正数,则刻度是小数点右侧的位数。如果为负数,则将数字的未缩放值乘以 10 的负数次方。因此 BigDecimal 表示的数字的值是 (unscaledValue × 10-scale)。

Double 有一定的精度。

已编辑: BigDecimal 是一个真实对象,而不是原始对象。因此,它抽象了数字表示,不受物理(读内存)限制。 礼貌: Max Leske

【讨论】:

  • 另外:BigDecimal 是一个真实对象,而不是原始对象(与double 相反。因此,它抽象了数字表示,不受物理(读取内存)限制。
【解决方案2】:

double 是一种非常快的浮点数据类型,在许多芯片组上以非常低的级别实现。

它的精度足以满足许多应用:例如测量太阳到冥王星的距离到最近的厘米!

在考虑迁移到更精确的数据类型时,总是需要权衡性能,因为后者会慢得多,而且您最喜欢的数学库可能不支持它们。请记住,程序的输出是输入质量的函数。

最后一点,千万不要使用双精度数来表示现金数量!

【讨论】:

    【解决方案3】:

    double 有 8 个字节来表示值,其精度限制为 15 位十进制数字,请参阅http://en.wikipedia.org/wiki/IEEE_754-1985。 BigDecimal 精度实际上是无限的,因为它基于任意长度的 int 数组。尽管使用 double 的操作比使用 BigDecimal 快得多,但这种数据类型绝不应该用于精确值,例如货币。

    【讨论】:

      【解决方案4】:

      当对BigDecimal 执行操作时,结果中的位数通常会大于任一操作数。这有两个主要影响:

      1. 除非代码强制定期舍入,否则BigDecimal 上的操作将随着数字越来越长而越来越慢。

      2. 没有固定大小的容器可能大到足以容纳BigDecimal,因为填充各自容器的两个值之间的许多操作会产生太长的结果,无法放入该大小的容器中。

      floatdouble 可以快速,而BigDecimal 不能快速的根本原因是它们被定义为在任何计算中尽可能多地降低精度,以便产生适合的结果在与原始操作数相同大小的容器中。这使他们能够使用固定大小的容器,而不必担心后续操作会变得越来越慢。

      顺便说一句,BigDecimal 速度慢的另一个主要(尽管不太基本)原因是值使用二进制格式的尾数表示,但使用十进制指数表示。因此,任何需要调整其操作数精度的操作都必须在一个非常昂贵的“规范化”步骤之前进行。如果任何给定值只有一种表示形式,则该类型可能更容易使用,因此将 123.456 与 0.044 相加得到 123.5 而不是 123.500,但将 123.500 归一化为 123.5 比将 123.456 和 0.44 相加需要更多的计算;此外,如果将该结果与小数点后三位有效数字相加,则在较早的相加之后执行的归一化将增加执行下一个所需的时间。

      【讨论】:

        【解决方案5】:

        为什么 BigDecimal 更精确?

        1. Double 在内存中的大小固定为 64 位(8 字节)。这将其精度限制为 15 到 17 位十进制数字。 BigDecimal 可以增长到您需要的任何大小。

        2. Double 以二进制运算,这意味着它只能精确地表示可以表示为二进制有限数的数字。例如,二进制的 0.375 正好是 0.011。 (换句话说,它是 2 的幂的和:它是 2-2 + 2-3。)但是像 0.1 这样的数字不能精确表示作为双精度,因为在二进制中它是0.0001100110011...,它不会终止。 BigDecimal 以十进制运行,因此它可以精确地表示 0.1 等我们熟悉的十进制数字。 (然而,虽然这扩大了可精确表示的值的范围,但它并没有消除潜在的问题;例如,值 三分之一 不能由任何一种类型精确表示,因为它具有非以二进制(0.010101...)和十进制(0.33333...)终止扩展。)

        用double计算有什么好处吗?

        绝对!

        1. 由于它占用的内存相对较少,因此 double 更适合长数字数组。

        2. Double 的固定二进制格式使其速度更快。它可以在软件和硬件上有效地处理。 CPU 在专用电路中实现双重算术。

        3. 使用 BigDecimal,对象可以在内存中任意增长,因为重复计算会产生更长的分数,但对于 double,您无需担心这一点,因为它的大小是固定的。

        为什么不能自定义 double 使其像 BigDecimal 一样工作?

        你得到你所支付的。 BigDecimal 可以更强大,但它的复杂性使计算速度变慢,占用更多内存,使用起来也更复杂。没有满足所有用例的数字数据类型,因此您必须根据应用程序的需要选择您想要的数据类型。

        【讨论】:

          【解决方案6】:

          使用double 进行计算比使用BigDecimal 快得多,因为它是一种原始类型,您还可以轻松完成所有数学运算。

          BigDecimal 非常棒,如果您需要执行非常精确的计算,但您为此付出了代价,例如无法轻松访问实际适用于 BigDecimal 的平方根函数并且通常计算速度要慢得多。

          【讨论】:

            【解决方案7】:

            由于我遇到的问题 Double 是它的精度值是有限的,所以当你使用超过限制的精度时,值将被四舍五入,但在 Big Decimal 的情况下你不会遇到这个问题

            【讨论】:

              【解决方案8】:

              根据定义,double 具有固定精度(以 2 为基数的 53 位)。它的主要优点是速度非常快,因为实际上基本操作完全在硬件中实现。如果这样的精度和/或基数 2 不适合您的应用程序,您可以使用任意精度算术。 BigDecimal 是标准的并使用基数 10。但是现在有 GNU MPFR Java bindings(我没有尝试过),因此您可以使用 GNU MPFR 库进行计算,该库使用基数 2 并且应该比 @ 快得多987654325@.

              【讨论】:

                猜你喜欢
                • 2023-02-22
                • 1970-01-01
                • 2012-09-05
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-11-06
                相关资源
                最近更新 更多