以前还真没这么在意过精度,这次因为要算数据,精确到万分之一,于是碰到了不少问题。
因为数据样本多,于是总有那么个不正常的。先举个例子
double preNum = 8;//6.4; double curNum = 8.53;//5.56; double r = curNum/preNum; System.out.println("r="+r);
打印出 r=1.06625 没有问题。那么换成后面注释的一组数6.4和5.56,那么打印出来的是r=0.8687499999999999,按理应该是0.86875
于是问题产生了,如果保留4为小数,0.86875是0.8688,而0.86874999,保留下来是0.8687,差了0.1
为了解决这个0.1,我开始想办法了。
一、放大到整数
本来想把都放大到整数,但用这两组数试了试,不行。正好相反了,如
double avgnum = curNum*100000/preNum;用8和8.53这组数,打印出来的是avgnum=106624.99999999999,另一组数正常了。
二、用BigDecimal
BigDecimal bPreNum = new BigDecimal(preNum); BigDecimal bCurNum = new BigDecimal(curNum); bCurNum.divide(bPreNum,6,BigDecimal.ROUND_HALF_UP).doubleValue();结果还是有问题。都说这个精度高,我没看出高在哪里,仔细研究了研究,
换成
BigDecimal bPreNum = new BigDecimal(preNum+""); BigDecimal bCurNum = new BigDecimal(curNum+""); bCurNum.divide(bPreNum,8,BigDecimal.ROUND_HALF_UP).doubleValue();没问题了,原来构造时用string精度能够保证。这里保留8位不是6位的原因是,例如0.6334495,这样保留6位是0.633450,在保留4位是0.6335,差了0.0001。
还剩下一组数忘了,碰到的是结果*100,也就是例如6.2356*100【因为忘了数据了,举个例子】,结果给我出来6.235599999,于是又用BigDecimal.
经过这次发现,如果要精度高点的,需要用到BigDecimal,不管乘除。
另外四舍五入的问题。
double ft = 98.425; java.text.DecimalFormat df =new java.text.DecimalFormat("#0.00"); String rtnf = df.format(ft); System.out.println("Format="+Double.valueOf(rtnf)); System.out.println("big="+new BigDecimal(ft).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()); System.out.println("big_100="+new BigDecimal(ft*100).setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue()/100);
打印出来结果是
Format=98.42
big=98.42
big_100=98.43
从这里可以看到,BigDecimal.ROUND_HALF_UP只对小数点后面一位数字有效。
上面的问题折腾了2天,总算搞明白各种差0.0001的原因。