java BigDecimal 模式详解
Java在java.math包中提供的API类BigDecimal,
用来对超过16位有效位的数进行精确的运算。
BigDecimal 是类似123.456这样的表示形式,
可以对数值进行切割,取舍,固定显示小数点后面几位,加减乘除等操作。
之前看了BigDecimal的使用,对BigDecimal里面的模式不是很清楚。
本文对BigDecimal中的模式进行详细介绍。
BigDecimal的模式是决定数值如何取舍
比如:
setScale方法,第一个参数表示保留小数点后面几位,第二个参数是模式值
BigDecimal.setScale(2,BigDecimal.ROUND_DOWN) 直接删除两位小数后面的小数, 1.235》1.23
BigDecimal.setScale(2,BigDecimal.ROUND_UP) 后面有数值,前面就要+1, 1.235》1.23
BigDecimal.setScale(2,BigDecimal.ROUND_HALF_UP) 四舍五入,向上取, 1.235》1.24
BigDecimal.setScale(2,BigDecimal.ROUND_HALF_DOWN) 四舍五入,向下取, 1.235》1.23 ,1.236》1.24
BigDecimal的模式是BigDecimal类中的静态值
有如下几个模式值:
public static final int ROUND_UP = 0;
public static final int ROUND_DOWN = 1;
public static final int ROUND_CEILING = 2;
public static final int ROUND_FLOOR = 3;
public static final int ROUND_HALF_UP = 4;
public static final int ROUND_HALF_DOWN = 5;
public static final int ROUND_HALF_EVEN = 6;
public static final int ROUND_UNNECESSARY = 7;
下面是所有模式值的详解
1、BigDecimal.ROUND_UP
oracle网页api中的解释翻译:
舍入模式从零舍入。始终在丢弃非零小数之前递增数字。注意,这种舍入模式永远不会减小计算值的大小。
但是和实际结果不同,查看类里面的说法和网页的也不一致,实际结果是绝对值比之前的大。
所以这里的计算值的大小的理解应该是不看正负的。
如下实际代码
String TAG = "TAG"
BigDecimal bigDecimal = new BigDecimal(1.234).setScale(2, BigDecimal.ROUND_UP);
Log.i(TAG, "1.234 BigDecimal.ROUND_UP = " + bigDecimal);
bigDecimal = new BigDecimal(-1.234).setScale(2, BigDecimal.ROUND_UP);
Log.i(TAG, "-1.234 BigDecimal.ROUND_UP = " + bigDecimal);
运行结果:
MainActivity: 1.234 BigDecimal.ROUND_UP = 1.24
MainActivity: -1.234 BigDecimal.ROUND_UP = -1.24
分析:
正数好理解:1.24 比 1.234 大,所以 1.234 》1.24
负数,其实ROUND_UP是不管前面正负,只看小数部分0.24 比 0.234 大,所以-1.234 》-1.24
这里还有个没执行的情况:1.230 》1.23,因为这里只说没减少但是也不一定会增大
但是只有后面有值就会增,比如:1.230000001 》1.24
2、BigDecimal.ROUND_DOWN
oracle网页api中的解释翻译:
舍入模式向零舍入。切勿在舍弃小数(即截断)之前增加数字。请注意,此舍入模式永远不会增加计算值的大小。
这个是最好理解的,就是直接截断,不管后面的数值是啥
如下实际代码
String TAG = "TAG"
BigDecimal bigDecimal = new BigDecimal(1.234).setScale(2, BigDecimal.ROUND_DOWN);
Log.i(TAG, "1.234 BigDecimal.ROUND_DOWN = " + bigDecimal);
bigDecimal = new BigDecimal(-1.234).setScale(2, BigDecimal.ROUND_DOWN);
Log.i(TAG, "-1.234 BigDecimal.ROUND_DOWN = " + bigDecimal);
运行结果:
MainActivity: 1.234 BigDecimal.ROUND_DOWN = 1.23
MainActivity: -1.234 BigDecimal.ROUND_DOWN = -1.23
3、BigDecimal.ROUND_CEILING
oracle网页api中的解释翻译:
舍入模式向正无穷大舍入。如果 BigDecimal为正,则表现为 ROUND_UP;
如果为负,则行为与相同 ROUND_DOWN。请注意,此舍入模式永远不会减少计算值。
这个也不难理解,正数情况就舍进,负数情况就直接舍去。
CEILING翻译是天花板的意思。表示高。
如下实际代码
String TAG = "TAG"
BigDecimal bigDecimal = new BigDecimal(1.234).setScale(2, BigDecimal.ROUND_CEILING);
Log.i(TAG, "1.234 BigDecimal.ROUND_CEILING = " + bigDecimal);
bigDecimal = new BigDecimal(-1.234).setScale(2, BigDecimal.ROUND_CEILING);
Log.i(TAG, "-1.234 BigDecimal.ROUND_CEILING = " + bigDecimal);
运行结果:
MainActivity: 1.234 BigDecimal.ROUND_CEILING = 1.24
MainActivity: -1.234 BigDecimal.ROUND_CEILING = -1.23
分析:
1.24不小于1.234
-1.23不小于-1.234
同样也是不一定保证一定大,比如:1.230 》1.23
4、BigDecimal.ROUND_FLOOR
oracle网页api中的解释翻译:
舍入模式向负无穷大舍入。此舍入模式永远不会增加计算值。
如果 BigDecimal为正,则按ROUND_DOWN;的方式行事 。
如果为负,则表现为 ROUND_UP。请注意,
这个也不难理解,正数情况就舍去,负数情况就直接舍进。
FLOOR翻译是地板的意思。表示低。
如下实际代码
String TAG = "TAG"
BigDecimal bigDecimal = new BigDecimal(1.234).setScale(2, BigDecimal.ROUND_FLOOR);
Log.i(TAG, "1.234 BigDecimal.ROUND_FLOOR = " + bigDecimal);
bigDecimal = new BigDecimal(-1.234).setScale(2, BigDecimal.ROUND_FLOOR);
Log.i(TAG, "-1.234 BigDecimal.ROUND_FLOOR = " + bigDecimal);
运行结果:
MainActivity: 1.234 BigDecimal.ROUND_FLOOR = 1.23
MainActivity: -1.234 BigDecimal.ROUND_FLOOR = -1.24
分析:
1.23不大于1.234
-1.24大大于-1.234
同样:1.230 》1.23 ,-1.230 》-1.23
5、BigDecimal.ROUND_HALF_UP 四舍五入
oracle网页api中的解释翻译:
舍入模式向“最近的邻居”舍入,除非两个邻居都等距,在这种情况下将舍入。
表现为ROUND_UP丢弃分数是否≥0.5;否则,行为与相同ROUND_DOWN。
请注意,这是我们大多数人在小学时所教的四舍五入模式。
half翻译是一半的意思。
从字面翻译就是大于等于一半后舍入。
大部分情况都是使用这种模式。
如下实际代码
String TAG = "TAG"
BigDecimal bigDecimal = new BigDecimal(1.234).setScale(2, BigDecimal.ROUND_FLOOR);
Log.i(TAG, "1.234 BigDecimal.ROUND_FLOOR = " + bigDecimal);
bigDecimal = new BigDecimal(-1.234).setScale(2, BigDecimal.ROUND_FLOOR);
Log.i(TAG, "-1.234 BigDecimal.ROUND_FLOOR = " + bigDecimal);
运行结果:
MainActivity: 1.234 BigDecimal.ROUND_HALF_UP = 1.23
MainActivity: -1.234 BigDecimal.ROUND_HALF_UP = -1.23
MainActivity: 1.235 BigDecimal.ROUND_HALF_UP = 1.24
MainActivity: -1.235 BigDecimal.ROUND_HALF_UP = -1.24
分析:
这里的四舍五入也是不看正负的,只对绝对值有效。
这个跟我们中学的是一样的,用的是靠近5原则,不管正负大小。
6、BigDecimal.ROUND_HALF_DOWN
oracle网页api中的解释翻译:
舍入模式向“最近的邻居”舍入,除非两个邻居都等距,在这种情况下舍入。行为ROUND_UP是否舍弃分数> 0.5;否则,行为与相同 ROUND_DOWN。
这种情况是一半也不舍入,要超过一半(6)才舍入
如下实际代码
String TAG = "TAG"
BigDecimal bigDecimal = new BigDecimal(1.234).setScale(2, BigDecimal.ROUND_FLOOR);
Log.i(TAG, "1.234 BigDecimal.ROUND_FLOOR = " + bigDecimal);
bigDecimal = new BigDecimal(-1.234).setScale(2, BigDecimal.ROUND_FLOOR);
Log.i(TAG, "-1.234 BigDecimal.ROUND_FLOOR = " + bigDecimal);
运行结果:
MainActivity: 1.234 BigDecimal.ROUND_HALF_DOWN = 1.23
MainActivity: -1.234 BigDecimal.ROUND_HALF_DOWN = -1.23
MainActivity: 1.235 BigDecimal.ROUND_HALF_DOWN = 1.24
MainActivity: -1.235 BigDecimal.ROUND_HALF_DOWN = -1.24
MainActivity: 1.236 BigDecimal.ROUND_HALF_DOWN = 1.24
MainActivity: -1.236 BigDecimal.ROUND_HALF_DOWN = -1.24
分析:
这个跟ROUND_HALF_UP类似,就是要以6为基准判断是否舍入舍去。
7、BigDecimal.ROUND_HALF_EVEN
oracle网页api中的解释翻译:
舍入模式向“最近的邻居”舍入,除非两个邻居都等距,则向相邻的偶数舍入。
如果舍弃部分左边的数字为奇数,则舍入行为与 ROUND_HALF_UP 相同;
如果为偶数,则舍入行为与 ROUND_HALF_DOWN 相同。
请注意,这是舍入模式,当在一系列计算中重复应用时,该模式可将累积误差最小化。
理解:
这个也是里面最难理解的一个。
就是要看舍弃的那位数值(<5)就舍去
舍弃的那位数值(>5)就舍进
如果刚好等于五,看前一位是奇数就舍进,偶数就舍去。
一句话:
即四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。
这种模式也是比较奇怪的,特殊场景才会用吧,网上把这个叫:银行家舍入
如下实际代码
String TAG = "TAG"
BigDecimal bigDecimal = new BigDecimal(1.234).setScale(2, BigDecimal.ROUND_HALF_EVEN);
Log.i(TAG, "1.234 BigDecimal.ROUND_HALF_EVEN = " + bigDecimal);
bigDecimal = new BigDecimal(-1.234).setScale(2, BigDecimal.ROUND_HALF_EVEN);
Log.i(TAG, "-1.234 BigDecimal.ROUND_HALF_EVEN = " + bigDecimal);
bigDecimal = new BigDecimal(1.235).setScale(2, BigDecimal.ROUND_HALF_EVEN);
Log.i(TAG, "1.235 BigDecimal.ROUND_HALF_EVEN = " + bigDecimal);
bigDecimal = new BigDecimal(-1.235).setScale(2, BigDecimal.ROUND_HALF_EVEN);
Log.i(TAG, "-1.235 BigDecimal.ROUND_HALF_EVEN = " + bigDecimal);
bigDecimal = new BigDecimal(1.245).setScale(2, BigDecimal.ROUND_HALF_EVEN);
Log.i(TAG, "1.235 BigDecimal.ROUND_HALF_EVEN = " + bigDecimal);
bigDecimal = new BigDecimal(-1.245).setScale(2, BigDecimal.ROUND_HALF_EVEN);
Log.i(TAG, "-1.235 BigDecimal.ROUND_HALF_EVEN = " + bigDecimal);
bigDecimal = new BigDecimal(1.236).setScale(2, BigDecimal.ROUND_HALF_EVEN);
Log.i(TAG, "1.236 BigDecimal.ROUND_HALF_EVEN = " + bigDecimal);
bigDecimal = new BigDecimal(-1.236).setScale(2, BigDecimal.ROUND_HALF_EVEN);
Log.i(TAG, "-1.236 BigDecimal.ROUND_HALF_EVEN = " + bigDecimal);
运行结果:
MainActivity: 1.234 BigDecimal.ROUND_HALF_EVEN = 1.23
MainActivity: -1.234 BigDecimal.ROUND_HALF_EVEN = -1.23
MainActivity: 1.235 BigDecimal.ROUND_HALF_EVEN = 1.24
MainActivity: -1.235 BigDecimal.ROUND_HALF_EVEN = -1.24
MainActivity: 1.245 BigDecimal.ROUND_HALF_EVEN = 1.24
MainActivity: -1.245 BigDecimal.ROUND_HALF_EVEN = -1.24
MainActivity: 1.236 BigDecimal.ROUND_HALF_EVEN = 1.24
MainActivity: -1.236 BigDecimal.ROUND_HALF_EVEN = -1.24
分析:
这里主要是看: 1.235 》1.245 ,5 前为奇数3,则舍进 ,
1.245 》1.24 ,5 前为偶数4,则舍去
8、BigDecimal.ROUND_UNNECESSARY
oracle网页api中的解释翻译:
舍入模式可以断言所请求的操作具有准确的结果,因此不需要舍入。如果在产生不精确结果的操作上指定了这种舍入模式,ArithmeticException则会引发an 。
这种是默认模式,但是有可能引发异常,不建议使用。
如果真要使用,应该是要配置其他参数的吧。
这个也是默认的值,网上说其他的值是默认,其实是不对的,源码如下:
public BigDecimal setScale(int newScale) {
return setScale(newScale, RoundingMode.UNNECESSARY);
}
如下实际代码
String TAG = "TAG"
BigDecimal bigDecimal = new BigDecimal(1.234).setScale(2, BigDecimal.ROUND_UNNECESSARY);
运行结果:
这个代码会运行异常,错误信息:Rounding necessary
但这里,BigDecimal的模式值就很详细的讲完了。
如果想详细看其他BigDecimal方法可以上官网看,或者下载api文档查看。
java1.8 api文档下载:https://download.csdn.net/download/wenzhi20102321/9619913
当然理解不透彻的地方,还是自己运行程序看是最容易理解的。