Double vs. BigDecimal?

我必须计算一些浮点变量,我的同事建议我使用BigDecimal而不是double因为它会更加精确。 但是我想知道它是什么以及如何最大限度地利用BigDecimal

BigDecimal是表示数字的确切方式。 Double有一定的精度。 使用不同大小的双精度(如d1=1000.0d2=0.001 )可能会导致0.001总和下降,因为在数量上的差异如此之大。 有了BigDecimal这不会发生。

BigDecimal的缺点是运行速度较慢,而且这样编程算法有点难(由于+ - */不被重载)。

如果您正在处理金钱,或者精确度是必须的,请使用BigDecimal 。 否则Doubles往往是够好的。

我建议阅读BigDecimal的javadoc ,因为他们解释的事情比我做的更好:)

我的英文不好,所以我只写一个简单的例子。

  double a = 0.02; double b = 0.03; double c = b - a; System.out.println(c); BigDecimal _a = new BigDecimal("0.02"); BigDecimal _b = new BigDecimal("0.03"); BigDecimal _c = _b.subtract(_a); System.out.println(_c); 

节目输出:

 0.009999999999999998 0.01 

有人还想用双? ;)

与double有两个主要区别:

  • 任意精度,类似于BigInteger,它们可以包含任意数量的精度和大小
  • 基10代替基2,BigDecimal是n * 10 ^尺度,其中n是任意大的有符号整数,尺度可以被认为是将小数点向左或向右移动的位数

您应该使用BigDecimal进行货币计算的原因不是它可以表示任何数字,而是它可以表示所有可以用十进制表示的数字,并且实际上包括货币世界中的所有数字(您绝不会传输1/3 $给某人)。

如果你想写下一个像十进制值一样的值,你会得到

 1/7 = 0.142857142857142857142857142857142857142857... 

与无限序列的142857.但是,因为你只能写下有限的数字的数字,你将不可避免地引入舍入(或截断)的错误。

不幸的是,1/10或1/100等数字表示为小数部分的二进制数,也有无限数量的小数二进制数。

 1/10 = binary 0.000110011001100110... 

将商店值加倍为二进制数字,因此可能仅通过将十进制数字转换为二进制数字而引入错误,甚至不进行任何算术运算。

另一方面,十进制数字(如BigDecimalBigDecimal原样存储每个十进制数字。 这意味着一个十进制类型不是一般意义上的二进制浮点或定点类型的精确性(例如,它不能存储1/7而没有精度损失),但是对于以有限数量的十进制数字,就像货币计算情况一样。

Java的BigDecimal还有一个额外的好处,就是它可以在小数点的两边都有一个任意的(但是是有限的)数字,只受限于可用的内存。

BigDecimal是Oracle的任意精度数值库。 BigDecimal是Java语言的一部分,对于从财务到科学等各种应用程序都是有用的。

使用双打进行某些计算没有任何问题。 不过,假设你想计算Math.Pi * Math.Pi / 6,即Riemann Zeta函数的值为两个实参(我目前正在研究的一个项目)。 浮点除法给你带来了一个令人头痛的错误的问题。

另一方面,BigDecimal包含许多用于以任意精度计算表达式的选项。 BigDecimal Java World中的“取代”+,*和/的Oracle文档中所述的添加,乘除法方法:

http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html

compareTo方法在while和for循环中特别有用。

但是,在使用BigDecimal的构造函数时要小心。 字符串构造函数在很多情况下非常有用。 例如,代码

BigDecimal onethird = new BigDecimal(“0.33333333333”);

利用1/3的字符串表示来将该无限重复的数字表示为指定的准确度。 舍入错误很可能是JVM内部非常深的地方,舍入错误不会干扰大部分实际计算。 但是,从个人经验来看,我已经看到了轮番上涨。 从这些Oracle文档中可以看出,setScale方法在这些方面非常重要。

原始数字类型可用于在存储器中存储单个值。 但是,在使用双精度和浮点类型进行计算时,四舍五入会出现问题,这是因为内存表示不能完全映射到值。 例如,double值应该占用64位,但Java不会使用全部64位。它只存储它认为是数字的重要部分。 所以,当你将float和double类型的值相加时,你可能会得到错误的值。 可能是这个视频https://youtu.be/EXxUSz9x7BM会解释更多;