前面介绍的BigInteger只能表达任意整数,但不能表达小数,要想表达任意小数,还需专门的大小数类型BigDecimal。如果说设计BigInteger的目的是替代int和long类型,那么设计BigDecimal的目的便是替代浮点型float和双精度型double了。正如它的兄弟BigInteger一般,BigDecimal不存在什么数值范围限制,无论是整数部分还是小数部分,只要你能写得出来,BigDecimal就能表达出来,从此不必担心基本数字类型的精度问题了。
既然同为大数字家族,BigDecimal的绝大部分用法就与BigInteger保持一致,像add方法、subtract方法、abs方法、pow方法等等直接拿来便是,这里不再重复啰嗦了,且看下面BigDecimal的方法调用代码:

		// 生成一个指定数值的大小数变量
BigDecimal sevenAndHalf = BigDecimal.valueOf(7.5);
BigDecimal three = BigDecimal.valueOf(3);
// add方法用来替代加法运算符“+”
BigDecimal sum = sevenAndHalf.add(three);
System.out.println("sum="+sum);
// subtract方法用来替代减法运算符“-”
BigDecimal sub = sevenAndHalf.subtract(three);
System.out.println("sub="+sub);
// multiply方法用来替代乘法运算符“*”
BigDecimal mul = sevenAndHalf.multiply(three);
System.out.println("mul="+mul);
// divide方法用来替代除法运算符“/”
BigDecimal div = sevenAndHalf.divide(three);
System.out.println("div="+div);
// remainder方法用来替代取余数运算符“%”
BigDecimal remainder = sevenAndHalf.remainder(three);
System.out.println("remainder="+remainder);
// negate方法用来替代负号运算符“-”
BigDecimal neg = sevenAndHalf.negate();
System.out.println("neg="+neg);
// abs方法用来替代数学库函数Math.abs
BigDecimal abs = sevenAndHalf.abs();
System.out.println("abs="+abs);
// pow方法用来替代数学库函数Math.pow
BigDecimal pow = sevenAndHalf.pow(2);
System.out.println("pow="+pow);

哇噻,难道这么容易就学会使用BigDecimal了吗?仔细看上面的例子代码,被除数是7.5,除数是3,二者相除得到的商为2.5。注意这是除得尽的情况,倘若换个除不尽的情况,例如把除数改成7,7.5除以7结果理应得到一个无限循环小数。可要是运行以下的测试代码,没想到程序竟然运行异常,未能打印那个值为无限循环小数的商。

		// 只有一个输入参数的divide方法,要求被除数能够被除数除得尽。
// 倘若除不尽,也就是商为无限循环小数,则程序会异常退出,
// 报错“Non-terminating decimal expansion; no exact representable decimal result.”
BigDecimal seven = BigDecimal.valueOf(7);
BigDecimal divTest = sevenAndHalf.divide(seven);
System.out.println("divTest="+divTest);

虽说大小数能够表示任意范围的小数,但必须是个有限的范围,而不能是无限的范围。由于内存容量是有限的,一个无限循环小数写出来都写不完,要是放到内存就需要无限大小的内存,因此为了让内存能够放得下无限循环小数,只好给该小数指定需要保留的小数位数,也就意味着BigDecimal表示无限循环小数时还是有精度要求的。
除了规定小数部分的保留位数,还需明确多余部分的数字是直接舍弃还是四舍五入?这样对于无限循环小数来说,除法运算的divide方法需要三个输入参数,包括除数、需要保留的小数位数、多余数字的舍入规则。BigDecimal提供的数字舍入规则主要有下列几种:
ROUND_CEILING:往数值较小的方向取整,类似于Math库的ceiling函数。
ROUND_FLOOR:往数值较大的方向取整,类似于Math库的floor函数。
ROUND_HALF_UP:四舍五入取整,若多余的数字等于.5,则前一位进1,类似于Math库的round函数。
ROUND_HALF_DOWN:类似四舍五入取整,区别在于:若多余的数字等于.5,则直接舍弃。
ROUND_HALF_EVEN:如果保留位数的末尾为奇数,则按照ROUND_HALF_UP方式取整。如果保留位数的末尾为偶数,则按照ROUND_HALF_DOWN方式取整。
由上述规则可知,通常情况下的四舍五入应当采取ROUND_HALF_UP方式。于是重新指定了小数精度和舍入规则,改写后大小数的除法运算代码示例如下:

		BigDecimal one = BigDecimal.valueOf(100);
BigDecimal three = BigDecimal.valueOf(3);
// 大小数的除法运算,小数点后面保留64位,其中最后一位做四舍五入
BigDecimal div = one.divide(three, 64, BigDecimal.ROUND_HALF_UP);
System.out.println("div="+div);

运行修改后的除法代码,控制台打印的日志结果见下:

div=33.3333333333333333333333333333333333333333333333333333333333333333

可见此时除法计算正常工作,并且结果值的小数部分确实保留到了64位。
上述带三个输入参数的divide方法固然实现了符合精度的除法运算,但若代码存在多处调用divide方法,便意味着该方法后面的精度规则“64, BigDecimal.ROUND_HALF_UP”在每处调用的地方都会出现,这样不但造成代码重复,而且要是变更精度规则还得改动多处。为此Java又提供了工具MathContext,利用该工具可事先指定包含小数精度和舍入规则在内的精度规则,然后把设置好的工具对象传给divide方法就好了。下面是使用MathContext工具辅助除法运算的代码例子:

		// 利用工具MathContext,可以把divide方法的输入参数减少为两个
MathContext mc = new MathContext(64, RoundingMode.HALF_UP);
BigDecimal divByMC = one.divide(three, mc);
System.out.println("divByMC="+divByMC);

在大小数的除法中引入精度工具MathContext,至少有两个好处,其一为:只要定义一次,即可多处使用;其二为:若要变更精度规则,只需修改一个地方。

更多Java技术文章参见《Java开发笔记(序)章节目录

Java开发笔记(三十)大小数BigDecimal的更多相关文章

  1. Java开发学习(三十六)----SpringBoot三种配置文件解析

    一. 配置文件格式 我们现在启动服务器默认的端口号是 8080,访问路径可以书写为 http://localhost:8080/books/1 在线上环境我们还是希望将端口号改为 80,这样在访问的时 ...

  2. 转:Java开发牛人十大必备网站

    原文来自于:http://www.importnew.com/7980.html 以下是我收集的Java开发牛人必备的网站.这些网站可以提供信息,以及一些很棒的讲座, 还能解答一般问题.面试问题等.质 ...

  3. Java开发牛人十大必备网站

    以下是我收集的Java开发牛人必备的网站.这些网站可以提供信息,以及一些很棒的讲座, 还能解答一般问题.面试问题等.质量是衡量一个网站的关键因素,我个人认为这些网站质量都很好.接下来,我会跟大家分享我 ...

  4. Java开发人员必备十大工具

    Java世界中存在着很多工具,从著名的IDE(例如Eclipse,NetBeans和IntelliJ IDEA)到JVM profiling和监视工具(例如JConsole,VisualVM,Ecli ...

  5. Java开发笔记(十)一元运算符的技巧

    前面讲到赋值运算符的时候,提到“x = x+7”可以被“x += 7”所取代,当然Java编程中给某个变量自加7并不常见,常见的是给某变量自加1,就像走台阶,一般都是一级一级台阶地走,犯不着一下子跳上 ...

  6. Java开发笔记(十九)规律变化的for循环

    前面介绍while循环时,有个名叫year的整型变量频繁出现,并且它是控制循环进出的关键要素.不管哪一种while写法,都存在三处与year有关的操作,分别是“year = 0”.“year<l ...

  7. Java学习笔记三十:Java小项目之租车系统

    Java小项目之租车系统 一:项目背景介绍: 根据所学知识,编写一个控制台版的“呱呱租车系统” 功能: 1.展示所有可租车辆: 2.选择车型.租车量: 3.展示租车清单,包含:总金额.总载货量以及其车 ...

  8. Java开发学习(三十)----Maven聚合和继承解析

    一.聚合 分模块开发后,需要将这四个项目都安装到本地仓库,目前我们只能通过项目Maven面板的install来安装,并且需要安装四个,如果我们的项目足够多,那么一个个安装起来还是比较麻烦的 如果四个项 ...

  9. Java开发学习(三十二)----Maven多环境配置切换与跳过测试的三种方式

    一.多环境开发 我们平常都是在自己的开发环境进行开发, 当开发完成后,需要把开发的功能部署到测试环境供测试人员进行测试使用, 等测试人员测试通过后,我们会将项目部署到生成环境上线使用. 这个时候就有一 ...

  10. Java开发学习(三十五)----SpringBoot快速入门及起步依赖解析

    一.SpringBoot简介 SpringBoot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化 Spring 应用的初始搭建以及开发过程. 使用了 Spring 框架后已经简化了我 ...

随机推荐

  1. 权限系统设计-day02

    练习中的问题: 1,<s:url action="employee_input" />这个标签用来让struts自动生成请求的路径,struts生成的路径是一个全路径, ...

  2. webpack 4.0 中 clean-webpack-plugin 的使用

    其实 clean-webpack-plugin 很容易知道它的作用,就是来清除文件的. 一般这个插件是配合 webpack -p 这条命令来使用,就是说在为生产环境编译文件的时候,先把 build或d ...

  3. 【RL-TCPnet网络教程】第32章 RL-TCPnet之Telnet服务器

    第32章      RL-TCPnet之Telnet服务器 本章节为大家讲解RL-TCPnet的Telnet应用,学习本章节前,务必要优先学习第31章的Telnet基础知识.有了这些基础知识之后,再搞 ...

  4. 平衡二叉树(AVL)介绍及其实现

    一.平衡二叉树 任何一个数据的查找过程都需要从根结点出发,沿某一个路径朝叶子结点前进.因此查找中数据比较次数与树的形态密切相关. 对于二叉树来说,当树中每个结点左右子树高度大致相同时,树高为logN. ...

  5. [Swift]LeetCode330. 按要求补齐数组 | Patching Array

    Given a sorted positive integer array nums and an integer n, add/patch elements to the array such th ...

  6. [Swift]LeetCode696. 计数二进制子串 | Count Binary Substrings

    Give a string s, count the number of non-empty (contiguous) substrings that have the same number of ...

  7. [Swift]LeetCode896. 单调数列 | Monotonic Array

    An array is monotonic if it is either monotone increasing or monotone decreasing. An array A is mono ...

  8. [Swift]LeetCode948. 令牌放置 | Bag of Tokens

    You have an initial power P, an initial score of 0 points, and a bag of tokens. Each token can be us ...

  9. POI生成EXCEL文件

    POI生成EXCEL文件 一.背景 根据指定格式的JSON文件生成对应的excel文件,需求如下 支持多sheet 支持单元格合并 支持插入图片 支持单元格样式可定制 需要 标题(title),表头( ...

  10. BBS论坛(二十)

    20.1.cms添加轮播图后台逻辑代码完成 (1)apps/models.py from exts import db from datetime import datetime class Bann ...