JAVA金额按比例分摊,零头处理
金额精确计算,必须使用 BigDecimal;
平均分摊,分摊的零头,一般都是由数据 “精度” 和分摊系数决定的;
主要是如何对零头进行处理,保证尽可能的平均分配。
1、按户均摊
/**
* 按户数分摊方式
* 分摊计算采用截取小数精确位数后的小数值BigDecimal.ROUND_DOWN
* 目的:指定金额200元,平均分配给6户,分摊前后金额相等
*/
private static void hsFt() {
BigDecimal[] repair_shou_Amt = new BigDecimal[6];// 每个分户应承担维修金额
BigDecimal fact_repair_Amt = new BigDecimal("0");// 维修对象的实际费用(不含零头)
//待分摊金额
BigDecimal ft_amt = new BigDecimal("200");
//分户总数
int count = repair_shou_Amt.length;
for(int i = 0; i < count; i++) {
//求每个分户的承担金额=分摊金额/总户数
repair_shou_Amt[i] =ft_amt.divide(new BigDecimal(count), 2, BigDecimal.ROUND_DOWN); //截掉精度之后的小数位的值
//实际分摊承担总金额---小数点截取后的总金额
fact_repair_Amt = fact_repair_Amt.add(repair_shou_Amt[i]);
}
// 零头 = 分摊实际承担金额-待分摊金额
BigDecimal repair_oddment_amt = fact_repair_Amt.subtract(ft_amt);
// 算出要参与分摊零头的户数-截掉精度后的小数位的值累加后的每个值假设最大也只可能为0.00999999999999999999无限接近0.01
int repair_int = repair_oddment_amt.multiply(new BigDecimal("100")).abs().intValue();
// 把维修金额零头分摊到分户上,如果参与维修零头的户数大于零或者小于总户数,则进行分摊,否则报错
if( (repair_int < count) && (repair_int > 0) ) {
// 如果零头小于零,则说明有repair_int个分户承担的金额少一分钱0.01,需要加一分钱
if( repair_oddment_amt.compareTo(new BigDecimal("0")) < 0 ) {
for(int i = 0; i < repair_int; i++) {
repair_shou_Amt[i] = repair_shou_Amt[i].add(new BigDecimal("0.01"));
}
}
else {
// 如果零头大于零,则说明有repair_int个分户承担的金额多一分钱0.01,需要减去一分钱
for(int i = 0; i < repair_int; i++) {
repair_shou_Amt[i] = repair_shou_Amt[i].subtract(new BigDecimal("0.01"));
}
}
}
else if( repair_int == 0 ) {
// 零头如果为零,不需要处理
}
else {
throw new BusinessException("非法操作!");
}
}
2、按面积均摊
/**
* 按面积分摊方式
* 分摊计算采用截取小数精确位数后的小数的值BigDecimal.ROUND_DOWN
* 目的:指定金额200元,平均分配给6户,每户面积可能不等,分摊前后金额相等
*/
public static void areaFt(){
BigDecimal[] repair_shou_Amt = new BigDecimal[6];// 每个分户应承担维修金额
BigDecimal fact_repair_Amt = new BigDecimal("0");// 维修对象的实际费用(不含零头)
//待分摊金额
BigDecimal ft_amt = new BigDecimal("200");
//分户总数
int count = repair_shou_Amt.length;
//分户面积
BigDecimal[]info_area = {new BigDecimal("20.12"),new BigDecimal("10.12"),new BigDecimal("11.12"),new BigDecimal("15.12"),new BigDecimal("10.12"),new BigDecimal("110.12")};
//分摊的总建面积
BigDecimal totalArea = ObjectUtil.getZeroBigDecimal();
for(int i = 0 ; i < count; i++){
totalArea=totalArea.add(info_area[i]);
}
for(int i = 0; i < count; i++) {
BigDecimal oa_hou_area = info_area[i];
//求每个分户的承担金额=(分户面积/总建筑面积)*分摊金额
repair_shou_Amt[i] = (oa_hou_area.multiply(ft_amt).divide(totalArea, 2, BigDecimal.ROUND_DOWN));//截掉精度之后的小数位的值
//实际分摊承担总金额---小数点截取后的总金额
fact_repair_Amt = fact_repair_Amt.add(repair_shou_Amt[i]);
}
// 零头 = 分摊实际承担金额-待分摊金额
BigDecimal repair_oddment_amt = fact_repair_Amt.subtract(ft_amt);
// 算出要参与分摊零头的户数-截掉精度后的小数位的值累加后的每个值假设最大也只可能为0.00999999999999999999无限接近0.01
int repair_int = repair_oddment_amt.multiply(new BigDecimal("100")).abs().intValue();
System.out.println(repair_int);
// 把维修金额零头分摊到分户上,如果参与维修零头的户数大于零或者小于总户数,则进行分摊,否则报错
if( (repair_int < count) && (repair_int > 0) ) {
// 如果零头小于零,则说明有repair_int个分户承担的金额少一分钱0.01,需要加一分钱
if( repair_oddment_amt.compareTo(new BigDecimal("0")) < 0 ) {
for(int i = 0; i < repair_int; i++) {
repair_shou_Amt[i] = repair_shou_Amt[i].add(new BigDecimal("0.01"));
}
}
else {
// 如果零头大于零,则说明有repair_int个分户承担的金额多一分钱0.01,需要减去一分钱
for(int i = 0; i < repair_int; i++) {
repair_shou_Amt[i] = repair_shou_Amt[i].subtract(new BigDecimal("0.01"));
}
}
}
else if( repair_int == 0 ) {
// 零头如果为零,不需要处理
}
else {
throw new BusinessException("非法操作!");
}
}
3、按随机均摊
/**
* 按面积分摊方式
* 分摊计算采用四舍五入BigDecimal.ROUND_HALF_UP
* 目的:指定金额200元,平均分配给6户,每户面积可能不等,分摊前后金额相等
*/
public static void otherFt(){
BigDecimal[] repair_shou_Amt = new BigDecimal[6];// 每个分户应承担维修金额
BigDecimal fact_repair_Amt = new BigDecimal("0");// 维修对象的实际费用(不含零头)
//待分摊金额
BigDecimal ft_amt = new BigDecimal("200");
//分户总数
int count = repair_shou_Amt.length;
//分户面积
BigDecimal[]info_area = {new BigDecimal("20.12"),new BigDecimal("10.12"),new BigDecimal("11.12"),new BigDecimal("15.12"),new BigDecimal("10.12"),new BigDecimal("110.12")};
//分摊的总建面积
BigDecimal totalArea = ObjectUtil.getZeroBigDecimal();
for(int i = 0 ; i < count; i++){
totalArea=totalArea.add(info_area[i]);
}
for(int i = 0; i < count; i++) {
BigDecimal oa_hou_area = info_area[i];
//求每个分户的承担金额=(分户面积/总建筑面积)*分摊金额
repair_shou_Amt[i] = (oa_hou_area.multiply(ft_amt).divide(totalArea, 2, BigDecimal.ROUND_HALF_UP));//四舍五入
//实际分摊承担总金额---小数点四舍五入后的总金额
fact_repair_Amt = fact_repair_Amt.add(repair_shou_Amt[i]);
}
// 零头 = 分摊实际承担金额-待分摊金额
BigDecimal repair_oddment_amt = fact_repair_Amt.subtract(ft_amt);
// 算出要参与分摊零头的户数-repair_int这个值的范围是由精度决定的,如果保留两位小数,则有且只可能存在1户
int repair_int = repair_oddment_amt.multiply(new BigDecimal("100")).abs().intValue();
System.out.println(repair_int);
// 把维修金额零头分摊到分户上,如果参与维修零头的户数大于零或者小于总户数,则进行分摊,否则报错
if( (repair_int < count) && (repair_int > 0) ) {
//取分摊分户中的某一户随机补或减0.01
Random rand = new Random();
int randNum = rand.nextInt(6);
System.out.println(randNum);
// 如果零头小于零,则说明有repair_int个分户承担的金额少一分钱0.01,需要加一分钱
if( repair_oddment_amt.compareTo(new BigDecimal("0")) < 0 ) {
repair_shou_Amt[randNum] = repair_shou_Amt[randNum].add(new BigDecimal("0.01"));
}
else {
// 如果零头大于零,则说明有repair_int个分户承担的金额多一分钱0.01,需要减去一分钱
repair_shou_Amt[randNum] = repair_shou_Amt[randNum].subtract(new BigDecimal("0.01"));
}
}
else if( repair_int == 0 ) {
// 零头如果为零,不需要处理
}
else {
throw new BusinessException("非法操作!");
}
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: