zoukankan      html  css  js  c++  java
  • Java之BigDecimal

      转载请注明源出处:http://www.cnblogs.com/lighten/p/6963836.html

    1.前言

      编程人员都应该知道计算机计算浮点数是不精确的,结果是近似数值,当然具体值还是和计算机操作的实现有关。因此,如果对于计算结果不需要过于精准的时候,使用浮点数类型是没什么问题的,但是如果要求精确值的话(比如计算利息),就不能使用这种不精确的结果了,而要选择java提供的用于计算精确浮点数的类BigDecimal。本文基于JDK1.8介绍此类的一般用法和源码实现。

      BigDecimal类注解的第一段就介绍了一些基本信息:不可变的、任意精度的十进制数。一个BigDecimal由任意精度的非刻度值整数和32位整数的刻度组成。如果值大于等于0,标度就是小数点后的位数,如果值小于0,值就是:非标度值*10^(-标度值)。这样说不好理解,后面会说明白构成。

      注意:上述的不可变指的并不是这个类被final修饰,而是指BigDecimal每次计算都是产生了一个新的对象,这点要注意。

    2.用例

         @Test
    	public void test() {
    		BigDecimal b = new BigDecimal(1.22);
    		System.out.println(b.unscaledValue());
    		System.out.println(b.scale());
    		System.out.println(b);
    		String a = "2199999999999999733546474089962430298328399658203125";
    		System.out.println(a.length());
    	}
    

      上述例子运行的结果是:

      由此可以看出以下几点:1.double类型是不精确的;2.上面所说的非刻度值就是指去掉了小数点的浮点数;3.刻度值指的就是小数点后面的位数了。

      正数的时候计算值是非刻度值+小数点位数构成,如12345 4就是1.2345,四位小数;负数的时候则是-12345*10^(-4)结果是-1.2345。

            @Test
    	public void testMathContext() {
    		BigDecimal add = new BigDecimal("1.17");
    		BigDecimal a = new BigDecimal("12.324", new MathContext(3, RoundingMode.UP));
    		BigDecimal b = new BigDecimal("12.324", new MathContext(2, RoundingMode.UP));
    		BigDecimal d = new BigDecimal("12.324", new MathContext(1, RoundingMode.UP));
    		BigDecimal c = new BigDecimal("12.324", new MathContext(0, RoundingMode.UP));
    		System.out.println(a);
    		System.out.println(a.add(add)); // a变成12.4
    		System.out.println(b.add(add));	// a变成14
    		System.out.println(d.add(add)); // a变成20
    		System.out.println(c.add(add));
    		
    	}

      上面一个例子展示了MathContext的用法,补充介绍了具体含义,这里说下第一个参数的作用,可以看出是设置了MathContext的那个BigDecimal在运算之前发生了变化。

    3.源码解读

      关键字段:

    private final BigInteger intVal;    // 无刻度整数(无小数点)
    private final int scale;            // 刻度值
    private transient int precision;  // 无小数点的整数的位数
    private final transient long intCompact;  //intVal如果其值小于Long.MAX_VALUE就可以紧凑的存储在这个字段方便计算

      BigDecimal有很多种构造方法:

      实际上也就是相互调用,主要的也就几个实现:首先所有具有BigInteger参数的构造方法都十分简单,大部分都是简单的赋值罢了。最多就是计算了一下intCompact的值:

      上述就是就是一个压缩过程,如果不能压缩就存一个标志位。

      入参为char和String的构造函数,最终调的都是方法:public BigDecimal(char[] in, int offset, int len, MathContext mc)。其它的int、long、double也都比较简单,int类型的时候intValue的值是null。总而言之,所有的构造方法,经过一系列运算,最终是要得到上面所列的四个关键字段的值。这些计算基本是位运算。值得一提的是可以通过静态valueof()方法来创建BigDecimal,过程大同小异。

      BigDecimal的运算函数:

        add();    // 加

        subtract()  // 减

        multiply()  // 乘

        divide()   // 除

        reminder()  //取余

        pow()    // 幂次方

        abs()    // 绝对值

        negate()  // 相反值(-this)

      等等,这里就不一一介绍了。

    4.补充

      之前构造函数中会看见MathContext这个参数,这里补充介绍一下相关内容。MathContext:制定BigDecimal运算操作的运算规则。其主要是通过两个属性来控制的:

        final int precision;  // 被用于计算的位数,0就是不限制位数

        final RoundingMode roundingMode;  // 运算时的舍入规则,有很多,可以看源码上的注释,有举例说明。

      默认使用的是无限制,ROUND_HALF_UP(无符号形式的四舍五入):1.1->1; 1.5->2.0; -1.1->-1.0; -1.5->-2.0

  • 相关阅读:
    深入理解JS中的变量及变量作用域
    浏览器加载、解析、渲染的过程
    gerrit和git
    宽高等比缩放
    常见的网站性能优化手段
    JS实现数组去重(重复的元素只保留一个)
    重构与回流
    APP开放接口API安全性——Token令牌Sign签名的设计与实现
    索引原理-btree索引与hash索引的区别
    从四个维度谈谈如何做好团队管理
  • 原文地址:https://www.cnblogs.com/lighten/p/6963836.html
Copyright © 2011-2022 走看看