不积跬步,无以至千里;
不积小流,无以成江海。
———荀子《劝学篇》
判断一个数是奇数还是偶数是小学里的基本知识,能够被 2 整除的整数是偶数,不能被 2 整除的数是奇数,这规则简单明了,还有什么可考虑的?好,我们来看一个例子,代码如下:
- 1 import java.util.Scanner;
- 2 3 public class Client21 {
- 4 public static void main(String[] args) {
- 5 // 接收键盘输入参数
- 6 Scanner input = new Scanner(System. in );
- 7 System.out.println("输入多个数字判断奇偶:");
- 8
- while (input.hasNextInt()) {
- 9 int i = input.nextInt();
- 10 String str = i + "-->" + (i % 2 == 1 ? "奇数": "偶数");
- 11 System.out.println(str);
- 12 13
- }
- 14
- }
- 15
- }
输入多个数字,然后判断每个数字的奇偶性,不能被 2 整除的就是奇数,其它的都是偶数,完全是根据奇偶数的定义编写的程序,我们开看看打印的结果:
输入多个数字判断奇偶:1 2 0 -1 -2 1--> 奇数 2--> 偶数 0--> 偶数 -1--> 偶数 -2--> 偶数
前三个还很靠谱,第四个参数 - 1 怎么可能是偶数呢,这 Java 也太差劲了吧。如此简单的计算也会出错!别忙着下结论,我们先来了解一下 Java 中的取余 (% 标识符) 算法,模拟代码如下:
- // 模拟取余计算,dividend被除数,divisor除数
- public static int remainder(int dividend, int divisor) {
- return dividend - dividend / divisor * divisor;
- }
看到这段程序,大家都会心的笑了,原来 Java 这么处理取余计算的呀,根据上面的模拟取余可知,当输入 - 1 的时候,运算结果为 - 1,当然不等于 1 了,所以它就被判定为偶数了,也就是我们的判断失误了。问题明白了,修正也很简单,改为判断是否是偶数即可。代码如下: i % 2 == 0 ? "偶数" : "奇数";
注意:对于基础知识,我们应该 "知其然,并知其所以然"。
在日常生活中,最容易接触到的小数就是货币,比如,你付给售货员 10 元钱购买一个 9.6 元的零食,售货员应该找你 0.4 元,也就是 4 毛钱才对,我们来看下面的程序:
- public class Client22 {
- public static void main(String[] args) {
- System.out.println(10.00 - 9.60);
- }
- }
我们的期望结果是 0.4,也应该是这个数字,但是打印出来的却是: 0.40000000000000036, 这是为什么呢?
这是因为在计算机中浮点数有可能(注意是有可能)是不准确的,它只能无限接近准确值,而不能完全精确。为什么会如此呢?这是由浮点数的存储规则所决定的,我们先来看看 0.4 这个十进制小数如何转换成二进制小数,使用 "乘 2 取整,顺序排列" 法(不懂,这就没招了,这太基础了),我们发现 0.4 不能使用二进制准确的表示,在二进制数世界里它是一个无限循环的小数,也就是说,"展示" 都不能 "展示",更别说在内存中存储了 (浮点数的存储包括三部分:符号位、指数位、尾数,具体不再介绍),可以这样理解,在十进制的世界里没有办法唯一准确表示 1/3,那么在二进制的世界里当然也无法准确表示 1/5(如果二进制也有分数的话倒是可以表示),在二进制的世界里 1/5 是一个无限循环的小数。
大家可能要说了,那我对结果取整不就对了吗?代码如下
- public class Client22 {
- public static void main(String[] args) {
- NumberFormat f = new DecimalFormat("#.##");
- System.out.println(f.format(10.00 - 9.60));
- }
- }
打印出的结果是 0.4,看似解决了。但是隐藏了一个很深的问题。我们来思考一下金融行业的计算方法,会计系统一般记录小数点后的 4 为小数,但是在汇总、展现、报表中、则只记录小数点后的 2 位小数,如果使用浮点数来计算货币,想想看,在大批量加减乘除后结果会有很大的差距 (其中还涉及到四舍五入的问题)!会计系统要求的就是准确,但是因为计算机的缘故不准确了,那真是罪过,要解决此问题有两种方法:
(1)、使用 BigDecimal
BigDecimal 是专门为弥补浮点数无法精确计算的缺憾而设计的类,并且它本身也提供了加减乘除的常用数学算法。特别是与数据库 Decimal 类型的字段映射时,BigDecimal 是最优的解决方案。
(2)、使用整型
把参与运算的值扩大 100 倍,并转为整型,然后在展现时再缩小 100 倍,这样处理的好处是计算简单,准确,一般在非金融行业 (如零售行业) 应用较多。此方法还会用于某些零售 POS 机,他们输入和输出的全部是整数,那运算就更简单了.
我们做一个小学生的题目,光速每秒 30 万公里,根据光线的旅行时间,计算月球和地球,太阳和地球之间的距离。代码如下:
- 1 public class Client23 {
- 2 // 光速是30万公里/秒,常量
- 3 public static final int LIGHT_SPEED = 30 * 10000 * 1000;
- 4 5 public static void main(String[] args) {
- 6 System.out.println("题目1:月球照射到地球需要一秒,计算月亮和地球的距离。");
- 7 long dis1 = LIGHT_SPEED * 1;
- 8 System.out.println("月球与地球的距离是:" + dis1 + " 米 ");
- 9 System.out.println("-------------------------------");
- 10 System.out.println("题目2:太阳光照射到地球需要8分钟,计算太阳到地球的距离.");
- 11 // 可能要超出整数范围,使用long型
- 12 long dis2 = LIGHT_SPEED * 60 * 8;
- 13 System.out.println("太阳与地球之间的距离是:" + dis2 + " 米");
- 14
- }
- 15
- }
估计有人鄙视了,这种小学生的乘法有神么可做的,不错,就是一个乘法运算,我们运行之后的结果如下:
题目 1:月球照射到地球需要一秒,计算月亮和地球的距离。
月球与地球的距离是:300000000 米
-------------------------------
题目 2:太阳光照射到地球需要 8 分钟,计算太阳到地球的距离.
太阳与地球之间的距离是:-2028888064 米
太阳和地球的距离竟然是负的,诡异。dis2 不是已经考虑到 int 类型可能越界的问题,并使用了 long 型吗,怎么还会出现负值呢?
那是因为 Java 是先运算然后进行类型转换的,具体的说就是因为 dis2 的三个运算参数都是 int 型,三者相乘的结果虽然也是 int 型,但是已经超过了 int 的最大值,所以其值就是负值了 (为什么是负值,因为过界了就会重头开始),再转换为 long 型,结果还是负值。
问题知道了,解决起来也很简单,只要加个小小的 L 即可,代码如下:
long dis2 = LIGHT_SPEED * 60L * 8;
60L 是一个长整型,乘出来的结果也是一个长整型的(此乃 Java 的基本转换规则,向数据范围大的方向转换,也就是加宽类型),在还没有超过 int 类型的范围时就已经转换为 long 型了,彻底解决了越界问题。在实际开发中,更通用的做法是主动声明类型转化 (注意,不是强制类型转换) 代码如下:
long dis2 = 1L * LIGHT_SPEED * 60L * 8
既然期望的结果是 long 型,那就让第一个参与的参数也是 Long(1L) 吧,也就说明 "嗨" 我已经是长整型了,你们都跟着我一块转为长整型吧。
注意:基本类型转换时,使用主动声明方式减少不必要的 Bug.
某商家生产的电子产品非常畅销,需要提前 30 天预订才能抢到手,同时还规定了一个会员可拥有的最多产品数量,目的是为了防止囤积压货肆意加价。会员的预订过程是这样的:先登录官方网站,选择产品型号,然后设置需要预订的数量,提交,符合规则即提示下单成功,不符合规则提示下单失败,后台的处理模拟如下:
- 1 import java.util.Scanner;
- 2 3 public class Client24 {
- 4 // 一个会员拥有产品的最多数量
- 5 public final static int LIMIT = 2000;
- 6 7 public static void main(String[] args) {
- 8 // 会员当前用有的产品数量
- 9 int cur = 1000;
- 10 Scanner input = new Scanner(System. in );
- 11 System.out.println("请输入需要预定的数量:");
- 12
- while (input.hasNextInt()) {
- 13 int order = input.nextInt();
- 14
- if (order > 0 && order + cur <= LIMIT) {
- 15 System.out.println("你已经成功预定:" + order + " 个产品");
- 16
- } else {
- 17 System.out.println("超过限额,预定失败!");
- 18
- }
- 19
- }
- 20 21
- }
- 22
- }
这是一个简单的订单处理程序,其中 cur 代表的是会员当前拥有的产品数量,LIMIT 是一个会员最多拥有的产品数量(现实中,这两个参数当然是从数据库中获得的,不过这里是一个模拟程序),如果当前预订数量与拥有数量之和超过了最大数量,则预订失败,否则下单成功。业务逻辑很简单,同时在 web 界面上对订单数量做了严格的校验,比如不能是负值、不能超过最大数量等,但是人算不如天算,运行不到两小时数据库中就出现了异常数据:某会员拥有的产品数量与预定数量之和远远大于限额。怎么会这样呢?程序逻辑上不可能有问题呀,这如何产生的呢?我们来模拟一下,第一次输入:
请输入需要预定的数量:800 你已经成功预定 800 个产品
这完全满足条件,没有任何问题,继续输入:
请输入需要预定的数量:2147483647 你已经成功预定 2147483647 个产品
看到没有,这个数字已经远远超过了 2000 的限额,但是竟然预定成功了,真实神奇!
看着 2147483647 这个数字很眼熟?那就对了,这个数字就是 int 类型的最大值,没错,有人输入了一个最大值,使校验条件失败了,Why?我们来看程序,order 的值是 2147483647 那再加上 1000 就超出 int 的范围了,其结果是 - 2147482649,那当然是小于正数 2000 了!一句归其原因:数字越界使校验条件失效。
在单元测试中,有一项测试叫做边界测试 (也叫临界测试),如果一个方法接收的是 int 类型的参数,那么以下三个值是必须测试的: 0、正最大、负最小,其中正最大、负最小是边界值,如果这三个值都没有问题,方法才是比较安全可靠的。我们的例子就是因为缺少边界测试,致使生产系统产生了严重的偏差。
也许你要疑惑了,Web 界面已经做了严格的校验,为什么还能输入 2147483647 这么大的数字呢?是否说明 Web 校验不严格? 错了,不是这样的,Web 校验都是在页面上通过 JavaScript 实现的,只能限制普通用户 (这里的普通用户是指不懂 html,不懂 HTTP,不懂 Java 的简单使用者),而对于高手,这些校验基本上就是摆设,HTTP 是明文传输的,将其拦截几次,分析一下数据结构,然后写一个模拟器,一切前端校验就成了浮云!想往后台提交个什么数据还不是信手拈来!
本建议还是来重温一个小学数学问题:四舍五入。四舍五入是一种近似精确的计算方法,在 Java5 之前,我们一般是通过 Math.round 来获得指定精度的整数或小数的,这种方法使用非常广泛,代码如下:
- public class Client25 {
- public static void main(String[] args) {
- System.out.println("10.5近似值: " + Math.round(10.5));
- System.out.println("-10.5近似值: " + Math.round( - 10.5));
- }
- }
输出结果为:10.5 近似值: 11 -10.5 近似值: -10
这是四舍五入的经典案例,也是初级面试官很乐意选择的考题,绝对值相同的两个数字,近似值为什么就不同了呢?这是由 Math.round 采用的舍入规则决定的 (采用的是正无穷方向舍入规则),我们知道四舍五入是由误差的:其误差值是舍入的一半。我们以舍入运用最频繁的银行利息计算为例来阐述此问题。
我们知道银行的盈利渠道主要是利息差,从储户手里收拢资金,然后房贷出去,期间的利息差额便是所获得利润,对一个银行来说,对付给储户的利息计算非常频繁,人民银行规定每个季度末月的 20 日为银行结息日,一年有 4 次的结息日。
场景介绍完毕,我们回头来看看四舍五入,小于 5 的数字被舍去,大于 5 的数字进位后舍去,由于单位上的数字都是自然计算出来的,按照利率计算可知,被舍去的数字都分布在 0~9 之间,下面以 10 笔存款利息计算作为模型,以银行家的身份来思考这个算法:
四舍:舍弃的数值是:0.000、0.001、0.002、0.003、0.004 因为是舍弃的,对于银行家来说就不需要付款给储户了,那每舍一个数字就会赚取相应的金额:0.000、0.001、0.002、0.003、0.004.
五入:进位的数值是:0.005、0.006、0.007、0.008、0.009,因为是进位,对银行家来说,每进一位就会多付款给储户,也就是亏损了,那亏损部分就是其对应的 10 进制补数:0.005、.0004、0.003、0.002、0.001.
因为舍弃和进位的数字是均匀分布在 0~9 之间,对于银行家来说,没 10 笔存款的利息因采用四舍五入而获得的盈利是:
0.000 + 0.001 + 0.002 + 0.003 + 0.004 - 0.005 - 0.004 - 0.003 - 0.002 - 0.001 = - 0.005;
也就是说,每 10 笔利息计算中就损失 0.005 元,即每笔利息计算就损失 0.0005 元,这对一家有 5 千万储户的银行家来说 (对国内银行来说,5 千万是个小数字),每年仅仅因为四舍五入的误差而损失的金额是:
银行账户数量(5 千万)*4(一年计算四次利息)*0.0005(每笔利息损失的金额)
5000*10000*0.0005*4=100000.0;即,每年因为一个算法误差就损失了 10 万元,事实上以上的假设条件都是非常保守的,实际情况可能损失的更多。那各位可能要说了,银行还要放贷呀,放出去这笔计算误差不就抵消了吗?不会抵消,银行的贷款数量是非常有限的其数量级根本无法和存款相比。
这个算法误差是由美国银行家发现的 (那可是私人银行,钱是自己的,白白损失了可不行),并且对此提出了一个修正算法,叫做银行家舍入(Banker's Round) 的近似算法,其规则如下:
以上规则汇总成一句话:四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。我们举例说明,取 2 位精度;
round(10.5551) = 10.56 round(10.555) = 10.56 round(10.545) = 10.56
要在 Java5 以上的版本中使用银行家的舍入法则非常简单,直接使用 RoundingMode 类提供的 Round 模式即可,示例代码如下:
- 1 import java.math.BigDecimal;
- 2 import java.math.RoundingMode;
- 3 4 public class Client25 {
- 5 public static void main(String[] args) {
- 6 // 存款
- 7 BigDecimal d = new BigDecimal(888888);
- 8 // 月利率,乘3计算季利率
- 9 BigDecimal r = new BigDecimal(0.001875 * 3);
- 10 //计算利息
- 11 BigDecimal i = d.multiply(r).setScale(2, RoundingMode.HALF_EVEN);
- 12 System.out.println("季利息是:" + i);
- 13 14
- }
- 15
- }
在上面的例子中,我们使用了 BigDecimal 类,并且采用了 setScale 方法设置了精度,同时传递了一个 RoundingMode.HALF_EVEN 参数表示使用银行家法则进行近似计算,BigDecimal 和 RoundingMode 是一个绝配,想要采用什么方式使用 RoundingMode 设置即可。目前 Java 支持以下七种舍入方式:
在普通的项目中舍入模式不会有太多影响,可以直接使用 Math.round 方法,但在大量与货币数字交互的项目中,一定要选择好近似的计算模式,尽量减少因算法不同而造成的损失。
注意:根据不同的场景,慎重选择不同的舍入模式,以提高项目的精准度,减少算法损失。
附录: 此处说的这些常量全部来自 java 的 RoundingMode 类,故而贴出此类的源码供大家参考。
- 1 package java.math;
- 2
- /**
- 3 * Specifies a <i>rounding behavior</i> for numerical operations
- 4 * capable of discarding precision. Each rounding mode indicates how
- 5 * the least significant returned digit of a rounded result is to be
- 6 * calculated. If fewer digits are returned than the digits needed to
- 7 * represent the exact numerical result, the discarded digits will be
- 8 * referred to as the <i>discarded fraction</i> regardless the digits'
- 9 * contribution to the value of the number. In other words,
- 10 * considered as a numerical value, the discarded fraction could have
- 11 * an absolute value greater than one.
- 12 *
- 13 * <p>Each rounding mode description includes a table listing how
- 14 * different two-digit decimal values would round to a one digit
- 15 * decimal value under the rounding mode in question. The result
- 16 * column in the tables could be gotten by creating a
- 17 * {@code BigDecimal} number with the specified value, forming a
- 18 * {@link MathContext} object with the proper settings
- 19 * ({@code precision} set to {@code 1}, and the
- 20 * {@code roundingMode} set to the rounding mode in question), and
- 21 * calling {@link BigDecimal#round round} on this number with the
- 22 * proper {@code MathContext}. A summary table showing the results
- 23 * of these rounding operations for all rounding modes appears below.
- 24 *
- 25 *<p>
- 26 *<table border>
- 27 * <caption><b>Summary of Rounding Operations Under Different Rounding Modes</b></caption>
- 28 * <tr><th></th><th colspan=8>Result of rounding input to one digit with the given
- 29 * rounding mode</th>
- 30 * <tr valign=top>
- 31 * <th>Input Number</th> <th>{@code UP}</th>
- 32 * <th>{@code DOWN}</th>
- 33 * <th>{@code CEILING}</th>
- 34 * <th>{@code FLOOR}</th>
- 35 * <th>{@code HALF_UP}</th>
- 36 * <th>{@code HALF_DOWN}</th>
- 37 * <th>{@code HALF_EVEN}</th>
- 38 * <th>{@code UNNECESSARY}</th>
- 39 *
- 40 * <tr align=right><td>5.5</td> <td>6</td> <td>5</td> <td>6</td> <td>5</td> <td>6</td> <td>5</td> <td>6</td> <td>throw {@code ArithmeticException}</td>
- 41 * <tr align=right><td>2.5</td> <td>3</td> <td>2</td> <td>3</td> <td>2</td> <td>3</td> <td>2</td> <td>2</td> <td>throw {@code ArithmeticException}</td>
- 42 * <tr align=right><td>1.6</td> <td>2</td> <td>1</td> <td>2</td> <td>1</td> <td>2</td> <td>2</td> <td>2</td> <td>throw {@code ArithmeticException}</td>
- 43 * <tr align=right><td>1.1</td> <td>2</td> <td>1</td> <td>2</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>throw {@code ArithmeticException}</td>
- 44 * <tr align=right><td>1.0</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td>
- 45 * <tr align=right><td>-1.0</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>-1</td>
- 46 * <tr align=right><td>-1.1</td> <td>-2</td> <td>-1</td> <td>-1</td> <td>-2</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>throw {@code ArithmeticException}</td>
- 47 * <tr align=right><td>-1.6</td> <td>-2</td> <td>-1</td> <td>-1</td> <td>-2</td> <td>-2</td> <td>-2</td> <td>-2</td> <td>throw {@code ArithmeticException}</td>
- 48 * <tr align=right><td>-2.5</td> <td>-3</td> <td>-2</td> <td>-2</td> <td>-3</td> <td>-3</td> <td>-2</td> <td>-2</td> <td>throw {@code ArithmeticException}</td>
- 49 * <tr align=right><td>-5.5</td> <td>-6</td> <td>-5</td> <td>-5</td> <td>-6</td> <td>-6</td> <td>-5</td> <td>-6</td> <td>throw {@code ArithmeticException}</td>
- 50 *</table>
- 51 *
- 52 *
- 53 * <p>This {@code enum} is intended to replace the integer-based
- 54 * enumeration of rounding mode constants in {@link BigDecimal}
- 55 * ({@link BigDecimal#ROUND_UP}, {@link BigDecimal#ROUND_DOWN},
- 56 * etc. ).
- 57 *
- 58 * @see BigDecimal
- 59 * @see MathContext
- 60 * @author Josh Bloch
- 61 * @author Mike Cowlishaw
- 62 * @author Joseph D. Darcy
- 63 * @since 1.5
- 64 */
- 65 public enum RoundingMode {
- 66 67
- /**
- 68 * Rounding mode to round away from zero. Always increments the
- 69 * digit prior to a non-zero discarded fraction. Note that this
- 70 * rounding mode never decreases the magnitude of the calculated
- 71 * value.
- 72 *
- 73 *<p>Example:
- 74 *<table border>
- 75 *<tr valign=top><th>Input Number</th>
- 76 * <th>Input rounded to one digit<br> with {@code UP} rounding
- 77 *<tr align=right><td>5.5</td> <td>6</td>
- 78 *<tr align=right><td>2.5</td> <td>3</td>
- 79 *<tr align=right><td>1.6</td> <td>2</td>
- 80 *<tr align=right><td>1.1</td> <td>2</td>
- 81 *<tr align=right><td>1.0</td> <td>1</td>
- 82 *<tr align=right><td>-1.0</td> <td>-1</td>
- 83 *<tr align=right><td>-1.1</td> <td>-2</td>
- 84 *<tr align=right><td>-1.6</td> <td>-2</td>
- 85 *<tr align=right><td>-2.5</td> <td>-3</td>
- 86 *<tr align=right><td>-5.5</td> <td>-6</td>
- 87 *</table>
- 88 */
- 89 UP(BigDecimal.ROUND_UP),
- 90 91
- /**
- 92 * Rounding mode to round towards zero. Never increments the digit
- 93 * prior to a discarded fraction (i.e., truncates). Note that this
- 94 * rounding mode never increases the magnitude of the calculated value.
- 95 *
- 96 *<p>Example:
- 97 *<table border>
- 98 *<tr valign=top><th>Input Number</th>
- 99 * <th>Input rounded to one digit<br> with {@code DOWN} rounding
- 100 *<tr align=right><td>5.5</td> <td>5</td>
- 101 *<tr align=right><td>2.5</td> <td>2</td>
- 102 *<tr align=right><td>1.6</td> <td>1</td>
- 103 *<tr align=right><td>1.1</td> <td>1</td>
- 104 *<tr align=right><td>1.0</td> <td>1</td>
- 105 *<tr align=right><td>-1.0</td> <td>-1</td>
- 106 *<tr align=right><td>-1.1</td> <td>-1</td>
- 107 *<tr align=right><td>-1.6</td> <td>-1</td>
- 108 *<tr align=right><td>-2.5</td> <td>-2</td>
- 109 *<tr align=right><td>-5.5</td> <td>-5</td>
- 110 *</table>
- 111 */
- 112 DOWN(BigDecimal.ROUND_DOWN),
- 113 114
- /**
- 115 * Rounding mode to round towards positive infinity. If the
- 116 * result is positive, behaves as for {@code RoundingMode.UP};
- 117 * if negative, behaves as for {@code RoundingMode.DOWN}. Note
- 118 * that this rounding mode never decreases the calculated value.
- 119 *
- 120 *<p>Example:
- 121 *<table border>
- 122 *<tr valign=top><th>Input Number</th>
- 123 * <th>Input rounded to one digit<br> with {@code CEILING} rounding
- 124 *<tr align=right><td>5.5</td> <td>6</td>
- 125 *<tr align=right><td>2.5</td> <td>3</td>
- 126 *<tr align=right><td>1.6</td> <td>2</td>
- 127 *<tr align=right><td>1.1</td> <td>2</td>
- 128 *<tr align=right><td>1.0</td> <td>1</td>
- 129 *<tr align=right><td>-1.0</td> <td>-1</td>
- 130 *<tr align=right><td>-1.1</td> <td>-1</td>
- 131 *<tr align=right><td>-1.6</td> <td>-1</td>
- 132 *<tr align=right><td>-2.5</td> <td>-2</td>
- 133 *<tr align=right><td>-5.5</td> <td>-5</td>
- 134 *</table>
- 135 */
- 136 CEILING(BigDecimal.ROUND_CEILING),
- 137 138
- /**
- 139 * Rounding mode to round towards negative infinity. If the
- 140 * result is positive, behave as for {@code RoundingMode.DOWN};
- 141 * if negative, behave as for {@code RoundingMode.UP}. Note that
- 142 * this rounding mode never increases the calculated value.
- 143 *
- 144 *<p>Example:
- 145 *<table border>
- 146 *<tr valign=top><th>Input Number</th>
- 147 * <th>Input rounded to one digit<br> with {@code FLOOR} rounding
- 148 *<tr align=right><td>5.5</td> <td>5</td>
- 149 *<tr align=right><td>2.5</td> <td>2</td>
- 150 *<tr align=right><td>1.6</td> <td>1</td>
- 151 *<tr align=right><td>1.1</td> <td>1</td>
- 152 *<tr align=right><td>1.0</td> <td>1</td>
- 153 *<tr align=right><td>-1.0</td> <td>-1</td>
- 154 *<tr align=right><td>-1.1</td> <td>-2</td>
- 155 *<tr align=right><td>-1.6</td> <td>-2</td>
- 156 *<tr align=right><td>-2.5</td> <td>-3</td>
- 157 *<tr align=right><td>-5.5</td> <td>-6</td>
- 158 *</table>
- 159 */
- 160 FLOOR(BigDecimal.ROUND_FLOOR),
- 161 162
- /**
- 163 * Rounding mode to round towards {@literal "nearest neighbor"}
- 164 * unless both neighbors are equidistant, in which case round up.
- 165 * Behaves as for {@code RoundingMode.UP} if the discarded
- 166 * fraction is ≥ 0.5; otherwise, behaves as for
- 167 * {@code RoundingMode.DOWN}. Note that this is the rounding
- 168 * mode commonly taught at school.
- 169 *
- 170 *<p>Example:
- 171 *<table border>
- 172 *<tr valign=top><th>Input Number</th>
- 173 * <th>Input rounded to one digit<br> with {@code HALF_UP} rounding
- 174 *<tr align=right><td>5.5</td> <td>6</td>
- 175 *<tr align=right><td>2.5</td> <td>3</td>
- 176 *<tr align=right><td>1.6</td> <td>2</td>
- 177 *<tr align=right><td>1.1</td> <td>1</td>
- 178 *<tr align=right><td>1.0</td> <td>1</td>
- 179 *<tr align=right><td>-1.0</td> <td>-1</td>
- 180 *<tr align=right><td>-1.1</td> <td>-1</td>
- 181 *<tr align=right><td>-1.6</td> <td>-2</td>
- 182 *<tr align=right><td>-2.5</td> <td>-3</td>
- 183 *<tr align=right><td>-5.5</td> <td>-6</td>
- 184 *</table>
- 185 */
- 186 HALF_UP(BigDecimal.ROUND_HALF_UP),
- 187 188
- /**
- 189 * Rounding mode to round towards {@literal "nearest neighbor"}
- 190 * unless both neighbors are equidistant, in which case round
- 191 * down. Behaves as for {@code RoundingMode.UP} if the discarded
- 192 * fraction is > 0.5; otherwise, behaves as for
- 193 * {@code RoundingMode.DOWN}.
- 194 *
- 195 *<p>Example:
- 196 *<table border>
- 197 *<tr valign=top><th>Input Number</th>
- 198 * <th>Input rounded to one digit<br> with {@code HALF_DOWN} rounding
- 199 *<tr align=right><td>5.5</td> <td>5</td>
- 200 *<tr align=right><td>2.5</td> <td>2</td>
- 201 *<tr align=right><td>1.6</td> <td>2</td>
- 202 *<tr align=right><td>1.1</td> <td>1</td>
- 203 *<tr align=right><td>1.0</td> <td>1</td>
- 204 *<tr align=right><td>-1.0</td> <td>-1</td>
- 205 *<tr align=right><td>-1.1</td> <td>-1</td>
- 206 *<tr align=right><td>-1.6</td> <td>-2</td>
- 207 *<tr align=right><td>-2.5</td> <td>-2</td>
- 208 *<tr align=right><td>-5.5</td> <td>-5</td>
- 209 *</table>
- 210 */
- 211 HALF_DOWN(BigDecimal.ROUND_HALF_DOWN),
- 212 213
- /**
- 214 * Rounding mode to round towards the {@literal "nearest neighbor"}
- 215 * unless both neighbors are equidistant, in which case, round
- 216 * towards the even neighbor. Behaves as for
- 217 * {@code RoundingMode.HALF_UP} if the digit to the left of the
- 218 * discarded fraction is odd; behaves as for
- 219 * {@code RoundingMode.HALF_DOWN} if it's even. Note that this
- 220 * is the rounding mode that statistically minimizes cumulative
- 221 * error when applied repeatedly over a sequence of calculations.
- 222 * It is sometimes known as {@literal "Banker's rounding,"} and is
- 223 * chiefly used in the USA. This rounding mode is analogous to
- 224 * the rounding policy used for {@code float} and {@code double}
- 225 * arithmetic in Java.
- 226 *
- 227 *<p>Example:
- 228 *<table border>
- 229 *<tr valign=top><th>Input Number</th>
- 230 * <th>Input rounded to one digit<br> with {@code HALF_EVEN} rounding
- 231 *<tr align=right><td>5.5</td> <td>6</td>
- 232 *<tr align=right><td>2.5</td> <td>2</td>
- 233 *<tr align=right><td>1.6</td> <td>2</td>
- 234 *<tr align=right><td>1.1</td> <td>1</td>
- 235 *<tr align=right><td>1.0</td> <td>1</td>
- 236 *<tr align=right><td>-1.0</td> <td>-1</td>
- 237 *<tr align=right><td>-1.1</td> <td>-1</td>
- 238 *<tr align=right><td>-1.6</td> <td>-2</td>
- 239 *<tr align=right><td>-2.5</td> <td>-2</td>
- 240 *<tr align=right><td>-5.5</td> <td>-6</td>
- 241 *</table>
- 242 */
- 243 HALF_EVEN(BigDecimal.ROUND_HALF_EVEN),
- 244 245
- /**
- 246 * Rounding mode to assert that the requested operation has an exact
- 247 * result, hence no rounding is necessary. If this rounding mode is
- 248 * specified on an operation that yields an inexact result, an
- 249 * {@code ArithmeticException} is thrown.
- 250 *<p>Example:
- 251 *<table border>
- 252 *<tr valign=top><th>Input Number</th>
- 253 * <th>Input rounded to one digit<br> with {@code UNNECESSARY} rounding
- 254 *<tr align=right><td>5.5</td> <td>throw {@code ArithmeticException}</td>
- 255 *<tr align=right><td>2.5</td> <td>throw {@code ArithmeticException}</td>
- 256 *<tr align=right><td>1.6</td> <td>throw {@code ArithmeticException}</td>
- 257 *<tr align=right><td>1.1</td> <td>throw {@code ArithmeticException}</td>
- 258 *<tr align=right><td>1.0</td> <td>1</td>
- 259 *<tr align=right><td>-1.0</td> <td>-1</td>
- 260 *<tr align=right><td>-1.1</td> <td>throw {@code ArithmeticException}</td>
- 261 *<tr align=right><td>-1.6</td> <td>throw {@code ArithmeticException}</td>
- 262 *<tr align=right><td>-2.5</td> <td>throw {@code ArithmeticException}</td>
- 263 *<tr align=right><td>-5.5</td> <td>throw {@code ArithmeticException}</td>
- 264 *</table>
- 265 */
- 266 UNNECESSARY(BigDecimal.ROUND_UNNECESSARY);
- 267 268 // Corresponding BigDecimal rounding constant
- 269 final int oldMode;
- 270 271
- /**
- 272 * Constructor
- 273 *
- 274 * @param oldMode The {@code BigDecimal} constant corresponding to
- 275 * this mode
- 276 */
- 277 private RoundingMode(int oldMode) {
- 278 this.oldMode = oldMode;
- 279
- }
- 280 281
- /**
- 282 * Returns the {@code RoundingMode} object corresponding to a
- 283 * legacy integer rounding mode constant in {@link BigDecimal}.
- 284 *
- 285 * @param rm legacy integer rounding mode to convert
- 286 * @return {@code RoundingMode} corresponding to the given integer.
- 287 * @throws IllegalArgumentException integer is out of range
- 288 */
- 289 public static RoundingMode valueOf(int rm) {
- 290
- switch (rm) {
- 291 292
- case BigDecimal.ROUND_UP:
- 293
- return UP;
- 294 295
- case BigDecimal.ROUND_DOWN:
- 296
- return DOWN;
- 297 298
- case BigDecimal.ROUND_CEILING:
- 299
- return CEILING;
- 300 301
- case BigDecimal.ROUND_FLOOR:
- 302
- return FLOOR;
- 303 304
- case BigDecimal.ROUND_HALF_UP:
- 305
- return HALF_UP;
- 306 307
- case BigDecimal.ROUND_HALF_DOWN:
- 308
- return HALF_DOWN;
- 309 310
- case BigDecimal.ROUND_HALF_EVEN:
- 311
- return HALF_EVEN;
- 312 313
- case BigDecimal.ROUND_UNNECESSARY:
- 314
- return UNNECESSARY;
- 315 316
- default:
- 317
- throw new IllegalArgumentException("argument out of range");
- 318
- }
- 319
- }
- 320
- }
来源: http://www.cnblogs.com/selene/p/5850216.html