bigDecimal学习
1.引言
float和double类型的主要设计目标是为了科学计算和工程计算。他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的。然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合。但是,商业计算往往要求结果精确,这时候BigDecimal就派上大用场啦。
先看下面代码

public static void main(String[] args)
{
System.out.println(0.2 + 0.1);
System.out.println(0.3 - 0.1);
System.out.println(0.2 * 0.1);
System.out.println(0.3 / 0.1);
}

运行结果如下

你认为你看错了,但结果却是是这样的。问题在哪里呢?原因在于我们的计算机是二进制的。浮点数没有办法是用二进制进行精确表示。我们的CPU表示浮点数由两个部分组成:指数和尾数,这样的表示方法一般都会失去一定的精确度,有些浮点数运算也会产生一定的误差。如:2.4的二进制表示并非就是精确的2.4。反而最为接近的二进制表示是 2.3999999999999999。浮点数的值实际上是由一个特定的数学公式计算得到的。
其实java的float只能用来进行科学计算或工程计算,在大多数的商业计算中,一般采用java.math.BigDecimal类来进行精确计算。
2.BigDecimal构造方法
1.public BigDecimal(double val) 将double表示形式转换为BigDecimal *不建议使用
2.public BigDecimal(int val) 将int表示形式转换成BigDecimal
3.public BigDecimal(String val) 将String表示形式转换成BigDecimal
为什么不建议采用第一种构造方法呢?来看例子

public static void main(String[] args)
{
BigDecimal bigDecimal = new BigDecimal(2);
BigDecimal bDouble = new BigDecimal(2.3);
BigDecimal bString = new BigDecimal("2.3");
System.out.println("bigDecimal=" + bigDecimal);
System.out.println("bDouble=" + bDouble);
System.out.println("bString=" + bString);
}

运行结果如下

为什么会出现这种情况呢?
JDK的描述:1、参数类型为double的构造方法的结果有一定的不可预知性。有人可能认为在Java中写入newBigDecimal(0.1)所创建的BigDecimal正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。
2、另一方面,String 构造方法是完全可预知的:写入 newBigDecimal("0.1") 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言,通常建议优先使用String构造方法。
当double必须用作BigDecimal的源时,请使用Double.toString(double)转成String,然后使用String构造方法,或使用BigDecimal的静态方法valueOf,如下

public static void main(String[] args)
{
BigDecimal bDouble1 = BigDecimal.valueOf(2.3);
BigDecimal bDouble2 = new BigDecimal(Double.toString(2.3)); System.out.println("bDouble1=" + bDouble1);
System.out.println("bDouble2=" + bDouble2); }

结果如下

3.BigDecimal加减乘除运算
对于常用的加,减,乘,除,BigDecimal类提供了相应的成员方法。

public BigDecimal add(BigDecimal value); //加法 public BigDecimal subtract(BigDecimal value); //减法 public BigDecimal multiply(BigDecimal value); //乘法 public BigDecimal divide(BigDecimal value); //除法

大概的用法如下

public static void main(String[] args)
{
BigDecimal a = new BigDecimal("4.5");
BigDecimal b = new BigDecimal("1.5"); System.out.println("a + b =" + a.add(b));
System.out.println("a - b =" + a.subtract(b));
System.out.println("a * b =" + a.multiply(b));
System.out.println("a / b =" + a.divide(b));
}

运行结果

这里有一点需要注意的是除法运算divide.
BigDecimal除法可能出现不能整除的情况,比如 4.5/1.3,这时会报错java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
其实divide方法有可以传三个参数
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
第一参数表示除数, 第二个参数表示小数点后保留位数,
第三个参数表示舍入模式,只有在作除法运算或四舍五入时才用到舍入模式,有下面这几种

ROUND_CEILING //向正无穷方向舍入 ROUND_DOWN //向零方向舍入 ROUND_FLOOR //向负无穷方向舍入 ROUND_HALF_DOWN //向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向下舍入, 例如1.55 保留一位小数结果为1.5 ROUND_HALF_EVEN //向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,如果保留位数是奇数,使用ROUND_HALF_UP,如果是偶数,使用ROUND_HALF_DOWN ROUND_HALF_UP //向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向上舍入, 1.55保留一位小数结果为1.6 ROUND_UNNECESSARY //计算结果是精确的,不需要舍入模式 ROUND_UP //向远离0的方向舍入

按照各自的需要,可传入合适的第三个参数。四舍五入采用 ROUND_HALF_UP
需要对BigDecimal进行截断和四舍五入可用setScale方法,例:

public static void main(String[] args)
{
BigDecimal a = new BigDecimal("4.5635"); a = a.setScale(3, RoundingMode.HALF_UP); //保留3位小数,且四舍五入
System.out.println(a);
}

*减乘除其实最终都返回的是一个新的BigDecimal对象,因为BigInteger与BigDecimal都是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象

public static void main(String[] args)
{
BigDecimal a = new BigDecimal("4.5");
BigDecimal b = new BigDecimal("1.5");
a.add(b); System.out.println(a); //输出4.5. 加减乘除方法会返回一个新的BigDecimal对象,原来的a不变 }

4.总结
(1)商业计算使用BigDecimal。
(2)尽量使用参数类型为String的构造函数。
(3) BigDecimal都是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,所以在做加减乘除运算时千万要保存操作后的值。
(4)我们往往容易忽略JDK底层的一些实现细节,导致出现错误,需要多加注意。
转载于https://www.cnblogs.com/LeoBoy/p/6056394.html
bigDecimal学习的更多相关文章
- Java的精确整数计算-Bigdecimal学习总结和工具类
随笔:随着最近工作需要,回首需要涉及到一些精确的数据计算,就需要用到Bigdecimal,索性就趁着闲暇之余整理收集一下关于Bigdecimal的使用方法,由于时间的原因,整理的并不是特别详细,但相信 ...
- java中BigDecimal的学习
干着java的活,但是看的都是一些偏底层的东西(或者我根本就没有看),有点荒废了java的学习. 最近一直在用到一个类是BigDecimal,但都是模棱两可地在那儿用,并没有深入研究这个类的细节,感觉 ...
- Java学习——BigInteger类和BigDecimal类
Java学习——BigInteger类和BigDecimal类 摘要:本文主要学习了用于大数字运算的BigInteger类和BigDecimal类. 部分内容来自以下博客: https://www.c ...
- 学习BigDecimal用法
一.简介 Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数.在实际应用中,需要对更大或者更 ...
- Java学习笔记26(Math类、Arrays类、BigInteger类、BigDecimal类)
Math类:数学工具类,做一些数学计算,开方,对数,三角函数等 所有方法都是静态方法,不需要建立对象,直接用类名调用即可 示例: 这里写几个在日常开发中会用到的,比如三角函数之类的平时不会用到,了解即 ...
- Java基础学习笔记之:System类;Math类;Arrays类BigInteger,BigDecimal
System类 在API中System类介绍的比较简单,我们给出定义,System中代表程序所在系统,提供了对应的一些系统属性信息,和系统操作.System类不能手动创建对象,因为构造方法被priva ...
- 【java】学习路径19-Math类、BigDecimal的使用
1--Math类简单的东西 //一些常数 show(Math.PI); show(Math.E); //四舍五入 show(Math.round(3.4)); show(Math.round(3.6) ...
- Java学习笔记(四)
字符串 字符串应用主要分为String类操作与字符串生成器 在程序中频繁的进行附加字符串则使用字符串生成器StringBuilder 数组 概述 数组是具有相同数据类型的一组数据的集合 数组创建 先声 ...
- effective java 学习心得
目的 记录一下最主要学习心得,不然凭我这种辣鸡记忆力分分钟就忘记白看了... 用静态工厂方法代替构造器的最主要好处 1.不必每次都创建新的对象 Boolean.valueOf Long.valueOf ...
随机推荐
- ptrdiff_t类型
一.特性 1. 这是一种标准库类型 2. 是两个指针相减的结果的类型(因为差值可能为负值,所以是一种带符号类型) 3. 和size_t一样,ptrdiff_t也是一种定义在<cstddef> ...
- zookeeper启动配置
zookeeper安装和配置详解 转载 2014年04月16日 14:36:31 16812 摘自:http://www.ibm.com/developerworks/cn/opensource/os ...
- iOS开发热更新JSPatch
JSPatch,只需在项目中引入极小的引擎,就可以使用JavaScript调用任何Objective-C的原生接口,获得脚本语言的能力:动态更新APP,替换项目原生代码修复bug. 是否有过这样的经历 ...
- lol人物模型提取(一)
前段时间去青岛搞团建去了,闲来无事逛了会儿淘宝,无想买个lol手办,意之间发现了这张店铺宣传图: 哎呀我去,这模型做得挺逼真啊,然而这家店铺是卖zoe的cosplay道具的,不是手办-_-|| ...
- 使用LoadRunner脚本采集Linux性能数据
前面介绍过在LoadRunner的Java协议实现“使用SSH连接Linux”.下面的脚本,是在LoadRunner里连接Linux/Unix远程服务器,收集其磁盘IO的负载到测试结果. 涉及到三个知 ...
- 织梦CMS建站入门学习(一)
一.下载与安装. 首先到织梦官网下载软件,可选择UTF8或GBK不同编码格式,如果电脑没有PHP环境,还要下载dede自带的PHP环境软件. 将软件中的upload文件夹内容复制到WWW文件夹下,然后 ...
- PHP中Session和Cookie的探究
一.Session (1)Session的由来以及介绍 Session:在计算机中,尤其是在网络应用中,称为“会话控制”,生存时间为用户在浏览某个网站时,从进入网站到关闭这个网站所经过的这段时间,也就 ...
- fzu1686-神龙的难题
给出一个n\times m的01矩阵,以及\(h,w\),表示一次可以把矩阵的一个\(h\times w\)的小矩阵变为全0,问至少要多少次可以把整个矩阵变为全0.\(n,m\le 15\). 分析 ...
- CentOS7 从查看、启动、停止服务说起systemctl
执行命令“systemctl status 服务名.service”可查看服务的运行状态,其中服务名后的.service 可以省略,这是CenOS7以后采用systemd作为初始化进程后产生的变化. ...
- 【刷题】SPOJ 1811 LCS - Longest Common Substring
A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the s ...