简体   繁体   English

为什么BigDecimal比double更为精确?

[英]Why is BigDecimal more precise than double?

I would like to know the exact difference between BigDecimal and double . 我想知道BigDecimaldouble之间的确切区别。 I know that BigDecimal is more precise than double and you should use the former for calculations. 我知道BigDecimaldouble更为精确,您应该使用前者进行计算。

Why is it more precise? 为什么更精确? Why isn't it possible to customize double so that it works like BigDecimal ? 为什么不能自定义double以使其像BigDecimal一样工作? Or are there any advantages to calculating with double ? 还是使用double进行计算有什么优势?

BigDecimal 大十进制

Immutable, arbitrary-precision signed decimal numbers. 不变的,任意精度的带符号十进制数字。 A BigDecimal consists of an arbitrary precision integer unscaled value and a 32-bit integer scale. BigDecimal由任意精度的整数无标度值和32位整数标度组成。 If zero or positive, the scale is the number of digits to the right of the decimal point. 如果为零或正数,则小数位数是小数点右边的位数。 If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale. 如果为负,则数字的未标度值将乘以十,即标度取反的幂。 The value of the number represented by the BigDecimal is therefore (unscaledValue × 10-scale). 因此,由BigDecimal表示的数字的值为(unscaledValue×10-scale)。

A Double has a certain precision. Double有一定的精度。

EDITED: BigDecimal is a real object, not a primitive one. 编辑: BigDecimal是一个真实的对象,而不是原始的对象。 Thus, it abstracts numerical representation and is not bound by physical (read memory) restrictions. 因此,它抽象了数字表示形式,并且不受物理(读存储器)限制的约束。 courtesy : Max Leske 礼貌: Max Leske

A double is a remarkably fast floating point data type implemented at a very low level on many chipsets. double是在许多芯片组上以非常低的级别实现的非常快的浮点数据类型。

Its precision is sufficient for very many applications: eg measuring the distance of the sun to Pluto to the nearest centimetre! 它的精度足以满足许多应用需求:例如,测量太阳到冥王星到最接近厘米的距离!

Always a performance trade-off when thinking about moving to a more precise data type as the latter will be much slower and your favourite mathematical libraries may not support them. 考虑迁移到更精确的数据类型时,始终要在性能上进行取舍,因为后者会慢得多,而且您最喜欢的数学库可能不支持它们。 Remember that the outputs of your program are a function of the quality of the inputs. 请记住,程序的输出是输入质量的函数。

As a final remark, never use a double to represent cash quantities though! 最后,请不要使用双倍来代表现金数量!

double has 8 bytes to represent the value, its precision is limited to 15 decimal digits, see http://en.wikipedia.org/wiki/IEEE_754-1985 . double有8个字节来表示值,其精度限制为15个十进制数字,请参见http://en.wikipedia.org/wiki/IEEE_754-1985 BigDecimal precision is de facto unlimited since it is based on an int array of arbitrary length. BigDecimal精度实际上是无限的,因为它基于任意长度的int数组。 Though operations with double are much faster than with BigDecimal this data type should never be used for precise values, such as currency. 尽管使用double进行运算要比使用BigDecimal进行运算要快得多,但该数据类型绝对不能用于货币等精确值。

When operations are performed on BigDecimal , the number of digits in the result will frequently be larger than either operand. 当对BigDecimal执行运算时,结果中的位数通常会大于两个操作数。 This has two major effects: 这有两个主要影响:

  1. Unless code forces periodic rounding, operations on BigDecimal will get slower and slower as the numbers get longer and longer. 除非代码强制进行定期舍入,否则随着数字越来越长, BigDecimal运算将越来越慢。

  2. No fixed-size container can possibly be big enough to accommodate a BigDecimal , since many operations between two values which filled up their respective containers would yield a result too long to fit into a container of that size. 固定大小的容器不可能足够大以容纳BigDecimal ,这是因为两个值之间的许多操作(它们填满了各自的容器)将导致结果太长而无法装入该大小的容器中。

The fundamental reason that float and double can be fast, while BigDecimal cannot, is that they are defined as lopping off as much precision as is necessary in any calculation so as to yield a result which will fit in the same size of container as the original operands. floatdouble可以很快而BigDecimal不能很快的根本原因是,它们被定义为在任何计算中都需要尽可能高的精度,以便产生与原始容器大小相同的结果操作数。 This enables them to use fixed-size containers, and not have to worry about succeeding operations becoming progressively slower. 这使他们能够使用固定大小的容器,而不必担心后续操作变得越来越慢。

Incidentally, another major (though less fundamental) reason that BigDecimal is slow is that values are represented using a binary-formatted mantissa but a decimal exponent. 顺便说一句, BigDecimal速度较慢的另一个主要原因(尽管不那么基本)是,值使用二进制格式的尾数表示,但使用十进制指数表示。 Consequently, any operations which would require adjusting the precision of their operands must be preceded by a very expensive "normalization" step. 因此,任何需要调整其操作数精度的操作都必须先执行非常昂贵的“规范化”步骤。 The type might be easier to work with if any given value had exactly one representation, and thus adding 123.456 to 0.044 yielded 123.5 rather than 123.500, but normalizing 123.500 to 123.5 would require much more computation than adding of 123.456 and 0.44; 如果任何给定值仅具有一个表示形式,则该类型可能更易于使用,因此将123.456添加到0.044会得到123.5,而不是123.500,但是将123.500标准化为123.5所需的计算要比添加123.456和0.44多得多。 further, if that result is added to another number with three significant figures after the decimal point, the normalization performed after the earlier addition would increase the time required to perform the next one. 此外,如果将该结果加到小数点后三位有效数字的另一个数字上,则在较早的加法之后执行的归一化将增加执行下一个数字所需的时间。

Why is BigDecimal more precise? 为什么BigDecimal更精确?

  1. Double's size in memory is fixed at 64 bits (8 bytes). 内存中Double的大小固定为64位(8字节)。 This limits it to 15 to 17 decimal digits of accuracy. 这将其精度限制为15到17个十进制数字。 BigDecimal can grow to any size you need it to. BigDecimal可以增长到您需要的任何大小。

  2. Double operates in binary which means it can only precisely represent numbers which can be expressed as a finite number in binary. Double以二进制形式操作,这意味着它只能精确表示可以用二进制形式表示为有限数的数字。 For example, 0.375 in binary is exactly 0.011. 例如,二进制的0.375恰好是0.011。 (To put it another way, it is a sum of powers of 2: it is 2 -2 + 2 -3 .) But a number like 0.1 cannot be precisely represented as a double, because in binary it is 0.0001100110011... , which doesn't terminate. (换句话说,它是2的幂的和。它是2 -2 + 2 -3 。)但是像0.1这样的数字不能精确地表示为双精度,因为在二进制中它是0.0001100110011 ... ,不会终止。 BigDecimal operates in decimal, so it can precisely represent numbers such as 0.1 that we are familiar with in decimal. BigDecimal以十进制运算,因此它可以精确地表示我们熟悉的数字(例如0.1)。 (However, although this expands the range of precisely representable values, it doesn't eliminate the underlying problem; for example, the value one third cannot be precisely represented by either type, because it has a non-terminating expansion in both binary (0.010101...) and decimal (0.33333...).) (但是,尽管这扩大了可精确表示的值的范围,但是并不能消除潜在的问题;例如, 三分之一的值不能用任何一种类型来精确表示,因为它在两个二进制值(0.010101 ...)和十进制(0.33333 ...)。)

Are there any advantages in calculating with double? 双精度计算有什么优势吗?

Absolutely! 绝对!

  1. Since it takes a comparatively tiny amount of memory, double is much better suited for long arrays of numbers. 由于它只占用很少的内存,因此double更好地适用于长数组。

  2. Double's fixed binary format makes it fast. Double的固定二进制格式使其速度更快。 It can be handled efficiently in both software and hardware. 它可以在软件和硬件中有效地处理。 CPUs implement double arithmetic in dedicated circuitry. CPU在专用电路中实现双重运算。

  3. With BigDecimal, the object can grow arbitrarily large in memory, because repeated computation can produce ever-longer fractions, but this isn't something you need to worry about with double since its size is fixed. 使用BigDecimal,对象可以在内存中任意增大,因为重复计算会产生越来越长的分数,但这并不是您需要担心的事情,因为它的大小是固定的,因此使用double可以不必担心。

Why isn't it possible to customize double so that it works like BigDecimal? 为什么不能自定义double以使其像BigDecimal一样工作?

You get what you pay for. 你得到你所付出的。 BigDecimal can be more powerful, but its sophistication makes computation slower, it takes more memory, and it is more complicated to use. BigDecimal可能更强大,但是其复杂性使计算速度变慢,占用更多内存,并且使用起来更加复杂。 There is no numeric data type that satisfies all use cases, so you have to pick which one you want depending on the needs of the application. 没有数字数据类型可以满足所有用例,因此您必须根据应用程序的需求选择所需的数据类型。

Calculating with double is much faster than with BigDecimal as it's a primative type you also have the full range of mathematical operations at your fingertips. 使用double计算比使用BigDecimal计算要快得多,因为它是原始类型,您还可以触及所有数学运算。

BigDecimal is great if you need to perform very precise calculations but you pay a price for that such as not having easy access to a square root function that actually works on a BigDecimal and generally much slower calculations. 如果需要执行非常精确的计算,则BigDecimal很棒,但是为此您要付出代价,例如无法轻松访问实际上可用于BigDecimal平方根函数,并且计算速度通常会慢得多。

由于我面对Double的问题是它的精度值受到限制,因此当您使用的精度超过限制时,该值将被四舍五入,但是如果使用Big Decimal,则您将不会遇到此问题

By definition, double has a fixed precision (53 digits in base 2). 根据定义, double具有固定的精度(以2为底的53位数字)。 Its main advantage is that it is very fast since in practice the basic operations are entirely implemented in hardware. 它的主要优点是非常快,因为实际上基本操作完全在硬件中实现。 If such a precision and/or base 2 are not adapted to your application, you can use an arbitrary-precision arithmetic. 如果这样的精度和/或基数2不适合您的应用程序,则可以使用任意精度算法。 BigDecimal is standard and uses base 10. However there now are GNU MPFR Java bindings (I haven't tried), so that you can do your computations with the GNU MPFR library, which uses base 2 and should be significantly faster than BigDecimal . BigDecimal是标准的,并使用10为底。但是现在有了GNU MPFR Java绑定 (我没有尝试过),因此您可以使用GNU MPFR库进行计算,该库使用2为底,并且应该比BigDecimal快得多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM