转载请注明源出处: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

Java之BigDecimal的更多相关文章

  1. java中BigDecimal加减乘除基本用法

    Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数. 在实际应用中,需要对更大或者更小的数进 ...

  2. Java中BigDecimal的8种舍入模式

    java.math.BigDecimal 不可变的.任意精度的有符号十进制数.BigDecimal 由任意精度的整数非标度值和32位的整数标度(scale)组成. 如果为零或正数,则标度是小数点后的位 ...

  3. java的BigDecimal

    java的BigDecimal 一般设计到高精度的加法或乘法或者阶乘的求和积都会用到BigDecimal这个类. import java.util.*;import java.math.BigDeci ...

  4. java.math.BigDecimal类

    BigDecimal类用于高精度计算.一般的float型和Double型数据只可以用来做科学计算或者是工程计算,由于在商业计算中,要求的数字精度比较高,所以要用到java.math.BigDecima ...

  5. Java中BigDecimal的8种舍入模式是怎样的

    Java中BigDecimal的8种舍入模式是怎样的?下面长沙欧柏泰克软件学院和大家一起来学习下吧:  java.math.BigDecimal 不可变的.任意精度的有符号十进制数.BigDecima ...

  6. java.math.BigDecimal()的用法

    Java中简单的浮点数类型float和double是不能进行运算的,不光Java,很多语言都是这样. 我们运行下面程序你将会看到 public class TestMathDecimal { publ ...

  7. 九度OJ题目1137:浮点数加法 (JAVA)使用BigDecimal四个案例都通过了,但是超时了。

    题目描述: 求2个浮点数相加的和 题目中输入输出中出现浮点数都有如下的形式: P1P2...Pi.Q1Q2...Qj 对于整数部分,P1P2...Pi是一个非负整数 对于小数部分,Qj不等于0 输入: ...

  8. Java使用BigDecimal保留double、float运算精度、保留指定位数有效数字、四舍五入

    工具类 package --; import java.math.BigDecimal; /** * Created by kongqw on 2015/12/10. */ public final ...

  9. Java 使用BigDecimal类处理高精度计算

    Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的 ...

  10. 数据转换失败 java.math.BigDecimal cannot be cast to java.lang.String

    从接口获取到数据,在转换的时候出现错误:java.math.BigDecimal cannot be cast to java.lang.String 因为一开始用的是使用关键字进行强制转换,后来发现 ...

随机推荐

  1. DevExpress TextEdit Focus问题

    在标签切换时设置第一个TextEdit获取输入焦点无效,需要采用消息Post方式设置 //标签切换事件 xtraTabControl1.Selected += (s, e) => { if (e ...

  2. IntelliJ IDEA 2017版 spring-boot使用Spring Data JPA搭建基础版的三层架构

    1.配置环境pom <?xml version="1.0" encoding="UTF-8"?> <project xmlns="h ...

  3. 教你把p标签的一行字掰弯文字换行): word-wrap: break-word;

    1 使用前的p是这样: 2  使用后: p{ word-wrap: break-word; overflow: hidden; } 3  又想变直: p{ word-wrap: normal; ove ...

  4. 关于this对象

    1.在全局函数中this指的是window 2.当函数被当做方法调用时,this等于那个对象 3.匿名函数具有全局性,只要是匿名函数,this指向window 实例1: var name = 'the ...

  5. (转)mmap和shm共享内存的区别和联系

    共享内存的创建 根据理论: 1. 共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制.共享内存可以通过mmap()映射普通文件 (特殊情况下还可以采用 ...

  6. smarty-2014-02-28

    使用smarty,在tpl文件中如何使用相对路径调用css&javascript文件,实际上这个相对路径的参照物就是以调用该tpl文件的php文件来写. 假如,我在index.php这个文件中 ...

  7. Delphi 动态与静态调用DLL(最好的资料)

    摘要:本文阐述了 Windows 环境下动态链接库的概念和特点,对静态调用和动态调用两种调用方式作出了比较,并给出了 Delphi 中应用动态链接库的实例. 一.动态链接库的概念    动态链接库(  ...

  8. Redis.conf配置文件内容详解

    #默认以后台方式运行 daemonize yes #指定redis pid文件 pidfile /data/apps/var/redis2/redis2.pid #指定redis启动占用的端口 por ...

  9. python中的 += 与 +

    这一部分首先要理解python内存机制,Python中万物皆对象. 对于不可变对象,改变了原来的值,其别名(变量名)绑定到了新值上面,id肯定会改变 对于可变对象,+ 操作改变了值,id肯定会变,而+ ...

  10. 微软官方实例 RazorPagesMovie 在 asp.net core 2.1 版本下的实战

    微软官方实例 RazorPagesMovie 在 asp.net core 2.1 版本下的实战 友情提示: 操作系统: MacOS 10.13.5 dotnet core: version 2.1. ...