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("非法操作!");
}
}
2、按随机均摊
/**
* 按面积分摊方式
* 分摊计算采用四舍五入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("非法操作!");
}
}
JAVA金额按比例分摊,零头处理的更多相关文章
- java金额的加减乘除
package com.wedge.edp.framework.common.util; import java.math.BigDecimal; /** * 金额的加减乘除 */ public cl ...
- java 金额的大小写转换类
/** *金额大小写转换工具类 */ public class MoneyUtil { /** 大写数字 */ private static final String[] NUMBERS = { &q ...
- java 金额计算,商业计算 double不精确问题 BigDecimal,Double保留两位小数方法
解决办法================== http://blog.javaxxz.com/?p=763 一提到Java里面的商业计算,我们都知道不能用float和double,因为他们无法 进行精 ...
- java 金额数字转换大写算法
根据人民币大写金额规范,转换有几点要注意的: 阿拉伯数字中间有"0"时,中文大写金额中间可以只写一个"零"字.如¥1,409.50,应写成人民币壹仟肆佰零玖圆伍 ...
- JAVA金额格式字符串转数值
项目中有时会遇到对金额格式的数值如“1,234.34567”进行计算,直接使用Double.parseDouble(“1,234.34567”)会抛出NumberFormatException异常, ...
- 前阿里CEO卫哲谈阿里创业经验:如何找人、找钱、找方向?(不同的阶段分别有:时间优先、金额优先、比例优先,不要做平台,太难)
新浪科技李根 整理报道 卫哲现在是御嘉基金的创始合伙人,他另一个更加知名的身份是阿里巴巴(B2B)前CEO,在2006年到2011年的时间里,卫哲见证了阿里巴巴如何利用人才.资本和方向选择一路壮大. ...
- Java生鲜电商平台-订单架构实战
Java生鲜电商平台-订单架构实战 生鲜电商中订单中心是一个电商后台系统的枢纽,在这订单这一环节上需要读取多个模块的数据和信息进行加工处理,并流向下一环节:因此订单模块对一电商系统来说,重要性不言而喻 ...
- Java生鲜电商平台-会员积分系统的设计与架构
Java生鲜电商平台-会员积分系统的设计与架构 说明:互联网平台积分体系主要用于激励和回馈用户在平台的消费行为和活动行为,一个良好的积分体系可以很好的提升用户的粘性及活跃度. 一.互联网平台积分体系设 ...
- 用“逐步排除”的方法定位Java服务线上“系统性”故障(转)
一.摘要 由于硬件问题.系统资源紧缺或者程序本身的BUG,Java服务在线上不可避免地会出现一些“系统性”故障,比如:服务性能明显下降.部分(或所 有)接口超时或卡死等.其中部分故障隐藏颇深,对运维和 ...
随机推荐
- php系统共享模板问题
我们在用php+html+css来写一个管理系统时,例如报名系统.投票系统,统计系统等,我们往往需要在管理后台查看每一位报名者的情况,问题接着就来了,由于比赛或者活动要求不同个,往往报名表不太一样,这 ...
- 设置Intellij IDEA 提示出未保存的*星号
IDEA实乃是java开发的神器,然而从eclipse或者MyEclipse转过来的开发每写完一行代码总是习惯的按下ctrl+s,然而IDEA代码编辑器的上方并没有提示未保存的*星号,提示星星,所以觉 ...
- 我做的第一个程序(菜鸟的java课堂笔记)
内存: 堆区,栈区,常量区,计数区,代码区: 数据类型: 基本数据类型:整形,浮点型,布尔型 boolean 只能返回真假值,字符型: 引用数据类型:类,数组: 基本数据类型-->直接存放到栈区 ...
- Web前端性能优化全攻略
网页制作poluoluo文章简介:Web 前端性能优化是个大话题,是个值得运维人员持续跟踪的话题,是被很多网站无情忽视的技术. Web 前端性能优化是个大话题,是个值得运维人员持续跟踪的话题,是被很多 ...
- 每天一个JS 小demo之树菜单。主要知识点:DOM方法综合运用,递归运用
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"& ...
- [css 实践篇] CSS box-orient
定义和用法 box-orient 属性规定框的子元素应该被水平或垂直排列. 提示:水平框中的子元素从左向右进行显示,而垂直框的子元素从上向下进行显示.不过,box-direction 和 box-or ...
- phpcms v9 调用自定义字段多图片的第一张或第N张图为缩略图
1.打开相应要使用组图的模型的组图字段,添加组图 字段提示为 <div class="content_attr"> <label><input typ ...
- 第一次接触Axure
现在已经是凌晨4:21了,我的第一份Axure.RP文件终于接近尾声,我带着些许疲倦些许兴奋的状态写下这篇博客,记录我和Axure的初遇. 三天前,我加入了湖南大学金山俱乐部,参加了第一次 ...
- PHP基础入门(四)---PHP数组实用基础知识
PHP数组 数组是特殊的变量,它可以同时保存一个以上的值. ***关键词:数组基础.数组遍历.超全局数组.数组功能.数组函数. 下面来和大家分享一下有关PHP的数组基础知识,希望对你PHP的学习有所帮 ...
- java 多线程访问同一个对象数据保护的问题
java 多线程同时访问统一个数据的时候,会引起一些错误,后面的线程会修改数据,而前面的线程还在使用修改前的内容, 使用 synchronized 关键字,保证代码块只能有一个线程来访问 public ...