X

Follow us on Facebook

Minimizing Distribution Error when Rounding off Decimals in Java

In continuation to my previous blog on preserving sum, there is an observation that we are just reducing/adding the differences to first element directly. At times this might sound very biased.

For example, say a number 11.456 is the first one, after rounding off the numbers using the ideology of previous post, if the difference was 0.01 (positive i.e., sum before rounding off is greater than sum after rounding by 0.01), then we would just add .01 to 11.46 (11.456 after rounding up gives 11.46). Resulting number is 11.47. Say there are two numbers like this in the series 11.456 and other is 9.459, going by our previous thoughts we would have the numbers like this 11.47 and 9.46.

Notice the irregularity - the number 11.456 which would've gained just 0.004 has gained .014 and the number 9.459 which gained only 0.001 has still gained only 0.001. In the world of even distributions and minimum errors it's not acceptable. It would be more good had 9.459 be made 9.47 and 11.456 made only 11.46.

So here's the solution for the above type of scenario in java




package com.test;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;

import com.model.Numb3r;

/**
* @author VinTech Blogs
*
*/
public class Digits {
public static final BigDecimal BASE_BIGDECIMAL = new BigDecimal("0.01");

public static void main(String args[]){
String[] from= {"3.2542","4.8796","5.2941","1.5642","5.4168","5.6249","7.6000"};
ArrayList gainedBDList= new ArrayList();
ArrayList lostBDList= new ArrayList();

Numb3r[] num = new Numb3r[from.length];
BigDecimal diff = new BigDecimal("0");
BigDecimal localDiff = new BigDecimal("0");

try{
for(int i=0; i< from.length; i++){
num[i] = new Numb3r(new BigDecimal(from[i]));
num[i].setDestBD(num[i].getSourceBD().setScale(2, RoundingMode.HALF_DOWN));
localDiff = num[i].getSourceBD().subtract(num[i].getDestBD());
num[i].setDiffBD(localDiff);
if(localDiff.doubleValue() > 0.0){
//insert into lostBDArray and sort
lostBDList.add(num[i]);

}else if(localDiff.doubleValue() <= 0.0){
//insert into gainedBDArray and sort
gainedBDList.add(num[i]);
}
diff = diff.add(num[i].getDiffBD());
}

Collections.sort(lostBDList);
Collections.sort(gainedBDList);

System.out.println(" Diff is "+diff);

//At this stage we would have sorted gainedBDArray(-0.0049, -.0032 etc) and
//lostBDArray (0.0011, 0.0025 etc)
if(diff.divide(BASE_BIGDECIMAL).intValue() >= 1){
lostBDList = positiveDistributor(lostBDList, gainedBDList, diff);
}else if(diff.divide(BASE_BIGDECIMAL).intValue() <= -1){
lostBDList = negativeDistributor(lostBDList, gainedBDList, diff);
}


for (Numb3r numb3r : lostBDList) {
System.out.println(numb3r.getDestBD());
}

}catch(Exception e){
e.printStackTrace();
}
}


public static ArrayList positiveDistributor(ArrayList lostBDList, ArrayList gainedBDList, BigDecimal diff ){
boolean flag = true;
for(int p=lostBDList.size()-1, q=gainedBDList.size()-1, k=diff.divide(BASE_BIGDECIMAL).abs().intValue();k>=1;p--){
//add to lost first
lostBDList.get(p).setDestBD(lostBDList.get(p).getDestBD().add(BASE_BIGDECIMAL));
k--;
if(flag && k > 1 && p > 0 && gainedBDList.get(q).getDiffBD().abs().compareTo(lostBDList.get(p-1).getDestBD().abs()) > 0){
gainedBDList.get(q).setDestBD(gainedBDList.get(q).getDestBD().subtract(BASE_BIGDECIMAL));
k++;
q--;
}else{
//never execute the above block again
flag = false;
}
}

lostBDList.addAll(gainedBDList);

return lostBDList;
}


public static ArrayList negativeDistributor(ArrayList lostBDList, ArrayList gainedBDList, BigDecimal diff ){
boolean flag = true;
for(int p=gainedBDList.size()-1, q=lostBDList.size()-1, k=diff.divide(BASE_BIGDECIMAL).abs().intValue();k>=1;p--){
//deduct from gained first
gainedBDList.get(p).setDestBD(gainedBDList.get(p).getDestBD().subtract(BASE_BIGDECIMAL));
k--;
if(flag && k > 1 && p > 0 && lostBDList.get(q).getDiffBD().abs().compareTo(lostBDList.get(p-1).getDestBD().abs()) > 0){
lostBDList.get(q).setDestBD(lostBDList.get(q).getDestBD().add(BASE_BIGDECIMAL));
k++;
q--;
}else{
//never execute the above block again
flag = false;
}
}

gainedBDList.addAll(lostBDList);

return gainedBDList;
}
}




Model class


package com.model;

import java.math.BigDecimal;

public class Numb3r implements Comparable{
private BigDecimal sourceBD;
private BigDecimal destBD;

private BigDecimal diffBD;

public Numb3r(BigDecimal sourceBD) {
this.sourceBD = sourceBD;
}

public BigDecimal getSourceBD() {
return sourceBD;
}

public void setSourceBD(BigDecimal sourceBD) {
this.sourceBD = sourceBD;
}

public BigDecimal getDestBD() {
return destBD;
}

public void setDestBD(BigDecimal destBD) {
this.destBD = destBD;
}

public BigDecimal getDiffBD() {
return diffBD;
}

public void setDiffBD(BigDecimal diffBD) {
this.diffBD = diffBD;
}

public int compareTo(Numb3r num) {
return this.getDiffBD().abs().compareTo(num.getDiffBD().abs());
}

}




Share on Google Plus

About Unknown

This is a short description in the author block about the author. You edit it by entering text in the "Biographical Info" field in the user admin panel.
    Blogger Comment
    Facebook Comment

0 comments:

Post a Comment