关于统计图表中的百分比之和不等于100的问题
一、问题描述:
最近用java Bigdecimal 四舍五入方式做了几个百分比统计图表,可是最后的几个汇总的和总是100.1,或者99.97。百度,google了好久。下面三种方案,第2)3)中还是会有处理不掉的情况,比如 1,1,1和是3。每个1/3 约等于33.33,没办法,我的选择是这种不做处理。三个都是1,凭啥其中一个就是33.34!
二、解决方案:
1)如果统计中有其他或者不重要的统计项的,这个不计算,等别的计算完了,再用100减去其他的和。
(听着挺合理 的,大家可以试试,我这个没有其他,所以这个不行)
2)google找到的一个帖子http://dovov.com/100-9.html 通过将小数部分递减的顺序加1来分配差异
3)这个我自创的,每次向前进一位,还是四舍五入,一直进到个位,如何还是不等于100,就不做处理。基本90%的情况都可以和变成100%。
三、相关代码
第 2)种的实现代码
public static void main(String[] args) {
getResultWithGoogleSuggestion();
}
private static void getResultWithGoogleSuggestion() { List<Double> result = new ArrayList<Double>(); // 13.626332% 47.989636% 9.596008% 28.788024 result.add(13.62); result.add(47.98); result.add(9.59); result.add(28.78); result.add(0d); Collections.sort(result, new Comparator<Double>() {//按小数点的指定位数排序 @Override public int compare(Double o1, Double o2) { return (getValue(String.valueOf(o2), 2))-(getValue(String.valueOf(o1), 2)); } }); double sum = 0; for (int i = 0; i < result.size(); i++) { sum = BigDecimalUtils.add(sum, result.get(i)); } double d=BigDecimalUtils.sub(sum,100); double b=turnLastToOne(d); int w=getTimes(d); boolean doOrNot=true; if(d>0){//和100比较大 Collections.reverse(result); if(getEquelsNum(result)>w){ doOrNot=false; } if(doOrNot) { for (int i = 0; i < w; i++) { result.set(i, BigDecimalUtils.sub(result.get(i), b)); } } }else if(d<0){//和比100小,要在指定几个上加上 if(getEquelsNum(result)>w){ doOrNot=false; } if(doOrNot) { for (int i = 0; i < w; i++) { result.set(i, BigDecimalUtils.sub(result.get(i), b)); } } } System.out.println(result); }
private static int getEquelsNum(List<Double> result) { int k=1; double dd=-1d; for(double d:result){ if(dd!=-1){ if(dd==d){ k++; } }else{ dd=d; } } return k; }
private static int getTimes(double d) { String s=String.valueOf(d); return Integer.parseInt(s.substring( s.length()-1,s.length())); }
private static double turnLastToOne(double d) {//获得指定位置上的数字 String s=String.valueOf(d); s=s.substring(0,s.length()-1); return Double.parseDouble(s+"1"); }
private static int getValue(String s, int position) {//获得指定位置上的数字 try { return Integer.parseInt(s.substring(s.indexOf(".") + position, s.indexOf(".") + position + 1)); }catch (StringIndexOutOfBoundsException e){ return -1; } }
第 3)种的实现代码
主方法:
/* 处理百分数之和大于100的问题 start*/ decimalPointGoUpOne(result,CommonConstants.ONE);//进一位看看 decimalPointGoUpOne(result,CommonConstants.ZERO);//如果不对,再进一位 /* 处理百分数之和大于100的问题 end*/ double sumResult=CommonConstants.DOUBLE_ZERO; for(int i=0;i<result.size();i++){ sumResult= BigDecimalUtils.add(sumResult,result.get(i)); } if (sumResult!=CommonConstants.ONE_HUNDRED){//进了2次都不能搞定,说明无限循环情况 result= result2;//返回原来的值 }
子方法:
private void decimalPointGoUpOne(List<Double> result,int scale) { double sumResult=CommonConstants.DOUBLE_ZERO; for(int i=0;i<result.size();i++){ sumResult= BigDecimalUtils.add(sumResult,result.get(i)); } if (sumResult!=CommonConstants.ONE_HUNDRED){ //通过将小数部分递减的顺序加1来分配差异 好厉害啊 for(int i=0;i<result.size();i++) { result.set(i,BigDecimalUtils.round(result.get(i),scale)); } } }
鄙人才疏学浅,代码仅供参考。有什么问题,还请各位大神不吝赐教。