`

java之BigDecimal

阅读更多
一、背景知识:

由于 java 中 double 所表示的精度是有限的,而且对于小数的运算不够准确。
java 提供了 BigDecimal 类,专门用于数的准确计算。这一点可以满足金融行业的需求。


二、正式开始:

BigDecimal 可以操作任意精度位数的十进制数字。

1、BigDecimal 由两部分组成:[unscaled value, scale]

1. 不定规模的值(unscaled value):
     该值是一个任意精度的整数(arbitrary precision integer)。

2. 规模(scale):
     是一个32位的整数(integer)。 可以用以下任一种方法:

     ● 如果 规模(scale)的值是 0 或 正数: 规模(scale)的值代表 BigDecimal 小数点右侧数字的个数。
        例如: [19,2] 所表示的值是: 0.19

     ● 如果 规模(scale)的值是 负数: 不定规模的值(unscaled value)乘以 10 的规模(scale)值的幂次方,得到 BigDecimal 真实值的大小。
        例如: [19,-2] 所表示的值是: 19 * 10⁻² = 0.19

    
2、BigDecimal 提供的操作:
     算数(加减乘除),规模控制,近似值,大小比较,哈希值,格式转换。


3、查看 BigDecimal 所表示的值:
     toString():     将 BigDecimal 所代表的值以字符串形式显示。如果有需要,会使用科学计数法显示。
     toPlainString(): 将 BigDecimal 所代表的值以字符串形式显示。不用科学计数法显示。


4、对于求近似值:
     如果一个数的小数部分是无限的(例如 1/3),而又没有指定取舍模式(rounding mode)(四舍五入、取整、等),则会抛出异常。
     如果一个数是有限的,可以通过使用 MathContext 对象指定计算时使用的精度(precision)和取舍模式(rounding mode)。


5、对于取舍模式:
     BigDecimal 类内部使用8个整型常量提供了8种取舍模式(如: ROUND_HALF_UP 四舍五入),但这种方法已被弃用。
     请使用 RoundingMode 对象的常量属性。(如: RoundingMode.HALF_UP )


6、对于精度:
精度计算:
     从运算结果的最左侧第一个不为0的数算起,直至末尾。
     例如:
           0.000042  的精度是 2
           0.0000420 的精度是 3


精度的值(jdk 1.5 及之前的版本):
     使用精度值为 0 (如: MathContext.UNLIMITED )的 MathContext 对象时,算数操作的结果是精确的。
     这是因为算数操作没有使用这个 MathContext 对象。由于没有指定精度,在操作无限数时会抛出异常。例如:除法运算 1/3

     使用精度值非0的 MathContext 对象时,算数的运算规则与 ANSI X3.274-1996 和 ANSI X3.274-1996/AM 1-2000 相兼容。
     BigDecimal 类还包含了其它的取舍模式。如果这些规则与 ANSI 标准相冲突,BigDecimal 会使用自己制定的运算规则。


7、对于运算结果的表示:
     使用算数运算和精度运算,对于运算结果的表示,必须指定数值结果(numerical result)和规模(scale)。
     因为:同一个值,因规模(scale)的不同,结果的表示也不同。


8、通常用法:
     如果运算结果的位数(可能是无限小数)大于需要的位数时,使用取舍模式和精度来共同决定运算结果如何返回。
     首先:使用 MathContext 对象设置精度。
     其次:使用 取舍模式决定要丢弃的尾部位数如何影响返回的结果。

     当取舍模式运算结果有进位而影响了所指定的精度时,则进位会被保留。
     如:对 999.9 做四舍五入,指定精度为 3位。返回值是:1000,此时输出结果为: 1.00 × 10³


9、算数操作的默认规模(scale)

    加法操作(a+b):    max(a.scale(), b.scale())
    减法操作(a-b):    max(a.scale(), b.scale())
    乘法操作(a*b):    a.scale() + b.scale()
    除法操作(a/b):    a.scale() - b.scale()
   
    特别注意:
    除法操作请指定规模,而不能使用默认的规模。
    例如: 1/32 的结果是 0.03125


10、算数操作的规模(scale)
   
     - 在对运算结果做取舍操作之前,逻辑中间运算结果的 scale 被默认设置为取舍运算的 scale。
     - 如果运算结果是无限小数,则运算结果的scale是根据设定的精度做取舍运算后得到的 scale。
     - 如果运算结果是有限数,则运算结果的scale会取值为最接近默认设置的 scale 。
       除法运算会使运算结果的 scale 变小,例如:
       scale 变小的情况: 19/100 = 0.19   // integer=19, scale=2
       scale 不变的情况: 21/110 = 0.190  // integer=190, scale=3
  
       注意:对于加法、减法、乘法,运算结果的 scale 的减小等于运算结果舍弃的位数。
             如果取舍运算有进位的情况,运算结果的附加数字将被丢弃。
        

11、两种会影响规模(scale)的操作:
    1. setScale()/round() 操作。返回 BigDecimal 类型。
    2. 小数点移动操作( movePointLeft() / movePointRight() )。返回 BigDecimal 类型。
   
12、注意:
    在使用具有大小排序功能的类时(如: SortedMap, SortedSet ),
    BigDecimal 不能按照其所代表的值的真实大小排序。因为 BigDecimal 的 equals() 方法与 BigDecimal 值的大小不符。
   
   
              


13、讨论:

(一)精度(precision)与规模(scale)

    BigDecimal b1 =  
    new BigDecimal("35.3456").round(new MathContext(4, RoundingMode.HALF_UP)); 
    System.out.println(b1.toString()); //result = 35.35

    BigDecimal b2 =  
    new BigDecimal("35.3456").setScale(4, RoundingMode.HALF_UP); 
    System.out.println(b2.toString()); // result = 35.3456



(二)有进位的情况

    BigDecimal b3 =    
        new BigDecimal("999.9").round(new MathContext(3, RoundingMode.HALF_UP));       
    System.out.println(b3.toString());       // 1.00E+3
        
    System.out.println(b3.toPlainString());  // 1000
    System.out.println(b3.precision());      // 3
       
        
    BigDecimal b4 = new BigDecimal("2000");                
    System.out.println(b4.toString());       // 2000


   
(三)与 double 比较

    double a = 0.02;
    double b = 0.03;
    double c = b - a;
    System.out.println(c);                       // 0.009999999999999998

    BigDecimal _a = new BigDecimal("0.02");
    BigDecimal _b = new BigDecimal("0.03");
    BigDecimal _c = _b.subtract(_a);
    System.out.println(_c);                      // 0.01

   
   
   
  







-
引用:
https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html



-
转载请注明
原文出处: http://lixh1986.iteye.com/blog/2323077
-





-

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics