您的位置:首页 > 其它

四舍五入你所不知道的事

2016-05-20 18:04 169 查看
今天我们来谈一谈四舍五入的问题,有人就站起来了,四舍五入有啥问题啊,大兄弟,咱冷静点,我既然提出来了,那说明里面的坑还是不少的,针对Math.round等一些方法我们今天不做分析,我们就来谈一谈格式化BigDecimal和DecmalFormat,是不是很熟悉,肯定用过是吧,如果你用过,但是却发现没遇到过坑,那你来对了,太粗心了有木有,先给个案例给大家:

DecimalFormat decimalFormat = new DecimalFormat("#0.00");
Log.e("***",decimalFormat.format(1.125)+"---"+decimalFormat.format(1.135));


请问输出啥?

1.13—1.14

????????????

问题出来了吧,请看打印结果:

1.12—1.14

懵逼了吧,发现坑了吧,没关系,我们来看一看api。

1、 ROUND_UP:远离零方向舍入。向绝对值最大的方向舍入,只要舍弃位非0即进位。 2、

ROUND_DOWN:趋向零方向舍入。向绝对值最小的方向输入,所有的位都要舍弃,不存在进位情况。 3、

ROUND_CEILING:向正无穷方向舍入。向正最大方向靠拢。若是正数,舍入行为类似于ROUND_UP,若为负数,舍入行为类似于ROUND_DOWN。Math.round()方法就是使用的此模式。

4、

ROUND_FLOOR:向负无穷方向舍入。向负无穷方向靠拢。若是正数,舍入行为类似于ROUND_DOWN;若为负数,舍入行为类似于ROUND_UP。

5、 HALF_UP:最近数字舍入(5进)。这是我们最经典的四舍五入。 6、 HALF_DOWN:最近数字舍入(5舍)。在这里5是要舍弃的。

7、 HAIL_EVEN:银行家舍入法。

这是什么?这是格式化的舍入方式,长见识了吧,跟我们平时遇到的不大一样吧,默认使用的是第七种银行家,为什么会这么设计呢,因为很多四舍五入都用在了金融方面,金融方面一个小数点都能导致翻天覆地的变化,影响极其大。比如说采取我们正常的四舍五入方式,

四舍:0.000、0.001、0.002、0.003、0.004

五入:0.005、0.006、0.007、0.008、0.009

银行遇到四舍的数字就舍弃成0.000,相当于赚了用户0.001、0.002、0.003、0.004相加的值,遇到五入的数字就进位成0.010,相当于亏了0.005、0.004、0.003、0.001相加的值,最后

0.001+0.002+0.003+0.004-0.005-0.004-0.003-0.002-0.001=0.005

别小看这0.005,基本上每十笔交易就亏损0.005,这是个很大的数字,所以才会出现银行家射入法:

舍去位的数值小于5时,直接舍去。 舍去位的数值大于5时,进位后舍去。

当舍去位的数值等于5时,若5后面还有其他非0数值,则进位后舍去,若5后面是0时,则根据5前一位数的奇偶性来判断,奇数进位,偶数舍去。

对于上面的规则我们举例说明

11.556 = 11.56 ——六入

11.554 = 11.55 —–四舍

11.5551 = 11.56 —–五后有数进位

11.545 = 11.54 —–五后无数,若前位为偶数应舍去

11.555 = 11.56 —–五后无数,若前位为奇数应进位、

这样就能有效地避免以上问题的发生。

于是上面的测试改成了如下:

DecimalFormat decimalFormat = new DecimalFormat("#0.00");
decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
Log.e("***", decimalFormat.format(1.125) + "---" + decimalFormat.format(1.135));


你说HALF_UP就是我们平时那种四舍五入的方式,那我们就测试下看看。

1.13—1.14

ok,果然对了,是不是到这就结束了呢,别急,还有坑呢。

DecimalFormat decimalFormat = new DecimalFormat("#0.00");       decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
Log.e("***", decimalFormat.format(1.125f) + "---" + decimalFormat.format(1.135f));


这不一样吗,不就是换成了浮点型吗?有啥区别啊,请看打印日志:

1.13—1.13

刺激不刺激?不信?自己试试啊!别怕,带你分析分析。

首先我们进入format源码

public final String format(double value) {
return format(value, new StringBuffer(), new FieldPosition(0)).toString();
}


人家只支持double类型的,但是我写float类型也不会报错,他会默认将float类型转为double类型,强转的话很容易导致进度丢失。所以才会出现我们上面这种情况,那么该如何解决呢?请看:

BigDecimal d = new BigDecimal(String.valueOf(1.125f));
BigDecimal r = new BigDecimal(String.valueOf(1.135f));
DecimalFormat decimalFormat = new DecimalFormat("#0.00");
decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
Log.e("***", Float.parseFloat(decimalFormat.format(d.doubleValue())) + "-----" + Float.parseFloat(decimalFormat.format(r.doubleValue())));


我们引入了BigDecimal来将float转为double型,

public BigDecimal(String val) {
this(val.toCharArray(), 0, val.length());
}


BigDecimal支持字符串类型,不会失精度,我们看下输出结果:

1.13—–1.14

ok,四舍五入的坑就讲到这里!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: