Java开发笔记(三十)大小数BigDecimal
前面介绍的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的更多相关文章
- Java开发学习(三十六)----SpringBoot三种配置文件解析
一. 配置文件格式 我们现在启动服务器默认的端口号是 8080,访问路径可以书写为 http://localhost:8080/books/1 在线上环境我们还是希望将端口号改为 80,这样在访问的时 ...
- 转:Java开发牛人十大必备网站
原文来自于:http://www.importnew.com/7980.html 以下是我收集的Java开发牛人必备的网站.这些网站可以提供信息,以及一些很棒的讲座, 还能解答一般问题.面试问题等.质 ...
- Java开发牛人十大必备网站
以下是我收集的Java开发牛人必备的网站.这些网站可以提供信息,以及一些很棒的讲座, 还能解答一般问题.面试问题等.质量是衡量一个网站的关键因素,我个人认为这些网站质量都很好.接下来,我会跟大家分享我 ...
- Java开发人员必备十大工具
Java世界中存在着很多工具,从著名的IDE(例如Eclipse,NetBeans和IntelliJ IDEA)到JVM profiling和监视工具(例如JConsole,VisualVM,Ecli ...
- Java开发笔记(十)一元运算符的技巧
前面讲到赋值运算符的时候,提到“x = x+7”可以被“x += 7”所取代,当然Java编程中给某个变量自加7并不常见,常见的是给某变量自加1,就像走台阶,一般都是一级一级台阶地走,犯不着一下子跳上 ...
- Java开发笔记(十九)规律变化的for循环
前面介绍while循环时,有个名叫year的整型变量频繁出现,并且它是控制循环进出的关键要素.不管哪一种while写法,都存在三处与year有关的操作,分别是“year = 0”.“year<l ...
- Java学习笔记三十:Java小项目之租车系统
Java小项目之租车系统 一:项目背景介绍: 根据所学知识,编写一个控制台版的“呱呱租车系统” 功能: 1.展示所有可租车辆: 2.选择车型.租车量: 3.展示租车清单,包含:总金额.总载货量以及其车 ...
- Java开发学习(三十)----Maven聚合和继承解析
一.聚合 分模块开发后,需要将这四个项目都安装到本地仓库,目前我们只能通过项目Maven面板的install来安装,并且需要安装四个,如果我们的项目足够多,那么一个个安装起来还是比较麻烦的 如果四个项 ...
- Java开发学习(三十二)----Maven多环境配置切换与跳过测试的三种方式
一.多环境开发 我们平常都是在自己的开发环境进行开发, 当开发完成后,需要把开发的功能部署到测试环境供测试人员进行测试使用, 等测试人员测试通过后,我们会将项目部署到生成环境上线使用. 这个时候就有一 ...
- Java开发学习(三十五)----SpringBoot快速入门及起步依赖解析
一.SpringBoot简介 SpringBoot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化 Spring 应用的初始搭建以及开发过程. 使用了 Spring 框架后已经简化了我 ...
随机推荐
- Ubuntu出现卡logo、卡住、黑屏无法正常启动、屏幕和键盘背光无法调节等一系列问题?可能是NVIDIA显卡驱动没装好
也不知道是幸运还是不幸,我从一开始接触ubuntu就遇到这一系列的问题, 而且一直没有一个彻底解决的办法,搞得我无比头疼,也害得我重装了无数遍系统... 国际惯例,只按照个人习惯和喜好来写,对某些人来 ...
- Mybatis Mapper文件中的一小坑
前几天来一需求,实现过程中需要修改一个底层的查询接口,具体修改就是在where中添加一个条件,由于这个底层SQL使用的地方太多,所以就想着是用if加一标识符做个判断,传一个只有我会使用的参数,然后动态 ...
- 实验三:分别用for,while;do-while循坏语句以及递归的方法计算n!,并输出算式。
源代码: package jiecheng;import java.util.Scanner;public class JieCheng {public static void main(String ...
- 二分(HDU2289 Cup)
贴代码: 题目意思:已知r水的下半径,R水的上半径,H为圆台高度,V为水的体积,求水的高度,如图: 水的高度一定在0-100,所以在这个区间逐步二分,对每次二分出的水的高度,计算相应的体积,看看计算出 ...
- Python连接MySQL数据库之pymysql模块使用
安装PyMySQL pip install pymysql PyMySQL介绍 PyMySQL是在python3.x版本中用于连接MySQL服务器的一个库,2中则使用mysqldb. Django中也 ...
- [Swift]LeetCode48. 旋转图像 | Rotate Image
You are given an n x n 2D matrix representing an image. Rotate the image by 90 degrees (clockwise). ...
- [Swift]LeetCode887. 鸡蛋掉落 | Super Egg Drop
You are given K eggs, and you have access to a building with N floors from 1 to N. Each egg is ident ...
- JSONP和CORS两种跨域方式的优缺点及使用方法原理介绍
随着软件开发分工趋于精细,前后端开发分离成为趋势,前端同事负责前端页面的展示及页面逻辑处理,服务端同事负责业务逻辑处理同时通过API为前端提供数据也为前端提供数据的持久化能力,考虑到前后端同事开发工具 ...
- 使用jquery实现返回顶部按钮
实现返回顶部效果,首先需要监听页面的scroll事件,其次才是获取到页面当前的滚动高度 $(window).scrollTop(); 具体代码如下: jquery获取页面元素的一些边界值(宽,高,滚动 ...
- Linux篇---Vi的使用
一.前述 Vi类似记事本,所以用好记事本对编程效率有很大得影响,有着事半功倍的效率. 二.具体操作 1.打开文件vim /path/to/somefilevim +# :打开文件,并定位于第#行 v ...