转载请注明源出处: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. Spring Cloud基础教程视频教程

    视频课程包含: Spring Cloud基础视频教程24G 目录 获取方式: 关注公众微信号:博涵大数据 或者扫描下面的二维码关注获取. 关注后在公众平台上回复"SpringCloud基础& ...

  2. AutoCompleteTextView

    在本节中作者只写了AutoCompleteTextView 和MutiAutoCompleteTextView 的用法,没有写怎样得到选中的值,我做了如下修改,增加按钮获取值赋值给TextView p ...

  3. 高翔《视觉SLAM十四讲》从理论到实践

    目录 第1讲 前言:本书讲什么:如何使用本书: 第2讲 初始SLAM:引子-小萝卜的例子:经典视觉SLAM框架:SLAM问题的数学表述:实践-编程基础: 第3讲 三维空间刚体运动 旋转矩阵:实践-Ei ...

  4. Java内存模型(二)

    volatile型变量的特殊规则 volatile是Java虚拟机提供的最轻量级的同步机制,当一个变量被定义成volatile后,它将具备两种特性,第一是保证此变量对所有线程的可见性,这里的“可见性” ...

  5. 团队项目(第三周)—GG队

    需求改进&系统设计 队员 学号 叶尚文(队长) 3116008802 蔡晓晴 3216008808 杜婷萱 3216008809 龙剑初 3116004647 于泽浩 3116004661 一 ...

  6. Python学习-33.Python中glob模块的一些参数

    glob模块中有一个叫glob的方法可以获取某个目录下的文件. import glob temp=glob.glob("E:\\Temp\\*.txt") print(temp) ...

  7. [ACM_数据结构] HDU 1166 敌兵布阵 线段树 或 树状数组

    #include<iostream> #include<cstdio> #include<memory.h> using namespace std; ]; //- ...

  8. .net core使用NLog记录

    首先使用Nugut安装NLog, NLog.Extensions.Logging,using NLog.Web,并且加上配置文件 ”nlog.config“,配置文件内容网上都可以百度的到.这是我自己 ...

  9. telerik自定义皮肤的制作及用法

    1. 打开telerik 官网 http://stylebuilder.telerik.com/ 2. 选择一个皮肤做为基础皮肤,并选择要制作的控件,并新取一个名字.比如选择皮肤Silk为基础皮肤,新 ...

  10. ! [rejected] master -> master (non-fast-forward)

    当向GitHub远程仓库提交请求时,常会出现  ! [rejected]  master -> master (non-fast-forward) 错误. 出现这种错误通常是由于远程仓库的文件版 ...