我正在尝试使用必要的多个BigDecimal计算工作的程序。我处于一个令人困惑的地步,因为BigDecimal没有合作我想要的。让我解释一下我需要它做什么:
首先,它需要一个最多可以有两个小数位的货币金额。然后它需要"分配"这基本上是多少账户的金额将通过。
该程序现在应该在帐户之间划分金额。当然,在某些情况下,金额不能平均分配,例如$ 3.33除以2个账户。在这种情况下,您必须要么有1分配额外的分数或围绕数字。舍入不是一种选择,必须考虑每一分钱。以下是我到目前为止的情况:
totalAllocations = TransactionWizard.totalAllocations;//Set in another class, how many accounts total will be spread
BigDecimal totalAllocationsBD = new BigDecimal(totalAllocations).setScale(2);//Converts to big decimal.
amountTotal = (BigDecimal) transInfo.get("amount"); // set total amount
MathContext mc = new MathContext(2);
remainderAllocation = amountTotal.remainder(totalAllocationsBD, mc);
dividedAllocationAmount = amountTotal.divide(totalAllocationsBD, MathContext.DECIMAL32);
dividedAllocationAmount=dividedAllocationAmount.setScale(2);
后来在课堂上我实际上写了这些值。我首先将一个计数器设置为totalAllocations。然后我有一个循环,它将写入一些信息,包括divideAllocationAmount。所以说amountTotal是10,我有两个分配然后5.00会被写两次。
我想要的是这样的情况,即总数不能在分配中平均分配,以便有一个额外的分配来保存余数,如下所示:
if(remainderAllocation.compareTo(BigDecimal.ZERO) >0 && allocationCounter==1){
adjAmt.setValue(remainderAllocation);
}else{
adjAmt.setValue(dividedAllocationAmount);
}
adjAmt只是设置一个XML字段,这是一个JAXB项目。
我在这里遇到的主要问题是带有余数的数字。例如,如果用户选择2个分配且金额为3.33美元,则程序将失败并给出舍入错误。
Exception in thread "AWT-EventQueue-0" java.lang.ArithmeticException: Rounding necessary
at java.math.BigDecimal.commonNeedIncrement(Unknown Source)
at java.math.BigDecimal.needIncrement(Unknown Source)
at java.math.BigDecimal.divideAndRound(Unknown Source)
at java.math.BigDecimal.setScale(Unknown Source)
at java.math.BigDecimal.setScale(Unknown Source)
at model.Creator.createTransaction(Creator.java:341)
at view.TransactionWizard$2.actionPerformed(TransactionWizard.java:333)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.WaitDispatchSupport$2.run(Unknown Source)
at java.awt.WaitDispatchSupport$4.run(Unknown Source)
at java.awt.WaitDispatchSupport$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.awt.WaitDispatchSupport.enter(Unknown Source)
at java.awt.Dialog.show(Unknown Source)
at java.awt.Component.show(Unknown Source)
at java.awt.Component.setVisible(Unknown Source)
at java.awt.Window.setVisible(Unknown Source)
at java.awt.Dialog.setVisible(Unknown Source)
at view.MainView$15$1.run(MainView.java:398)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Local Instrument: WEB
如果总金额为10.51美元并且有3个分配,则会发生同样的情况。实际上我想要的是两个分配为5.25美元,第三个分配为0.01美元。 (因为那是剩下的)。我该怎么办?
答案 0 :(得分:2)
当然在某些情况下,金额不能均分, 例如$ 3.33除以2个账户。在那种情况下你必须 要么有1分配额外分或数字
[没有优化,最佳实践,错误处理,数据类型转换等普通工作伪代码。]
试试这个
float amount = 3.33f;
int allocations = 2;
double average = amount/allocations;
System.out.println("ACTUAL AVERAGE "+average);
double rounded = Math.round(average * 100.0) / 100.0;
System.out.println("ROUNDED VALUE: "+rounded);
double adjustment = average - rounded;
adjustment*=allocations; //-- FOR EACH ALLOCATION
for(int i=1; i<allocations; i++){
System.out.println("Allocation :" +i + " = "+rounded);
}
//-- ADDING ADJUSTED ROUNDING AMOUNT TO LAST ONE
double adjustedAmount = Math.round((rounded+adjustment) * 100.0) / 100.0;
System.out.println("Allocation :" +allocations +" = " + adjustedAmount);
输出金额3.33,分配2次。
ACTUAL AVERAGE 1.6649999618530273
ROUNDED VALUE: 1.66
Allocation :1 = 1.66
Allocation :2 = 1.67 //-- EXTRA CENT
如果总金额为10.51美元并且有3个,则会发生同样的情况 分配。实际上我想要的是两个分配 5.25美元,第三次拨款为0.01美元。 (因为那是 剩余)。我该怎么办?
现在这与上面所说的不同,你可以拥有3.5,3.5&amp; 3.51。
但如果你想单独使用0.01,那么改变上面的代码分配-1&amp;将余数设置为最后一次分配。因此对于2&amp;第三次分配的余数为0.01,希望这有帮助。
答案 1 :(得分:0)
我终于通过自己的反复试验找到了解决这个问题的方法。事实证明,对我而言,关键在于取出其余部分,然后进行分割。
因为我知道我想根据情况自动将大十进制分成三个部分,我这样做..
package mathtest;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
public class MathTest
{
public static BigDecimal totalAmount;
public static BigDecimal totalAllocations;
public static BigDecimal divisibleAmount;
public static BigDecimal remainderAmount;
public static BigDecimal subtractDecimal;
public static void main(String args[]){
MathContext mc = new MathContext(2);
totalAmount = new BigDecimal(10.00).setScale(2,RoundingMode.HALF_UP);//Sets the total monetary amount. Standard monetary rounding.
totalAllocations = new BigDecimal(2);//The number of accounts the total amount will be split between.
subtractDecimal = new BigDecimal(1.00);//Used to remove one from the total allocations (to account for the remainder).
remainderAmount = totalAmount.remainder(totalAllocations, mc);//Gets the remainder assuming you tried to divide total/allocations.
totalAmount=totalAmount.subtract(remainderAmount);//Subtracts the remainder from the total.
if(remainderAmount.compareTo(BigDecimal.ZERO) >0){//If there is a remainder.
//The divisible amount is the total amount divided by the total allocations minus 1 (to account for remainder).
divisibleAmount=totalAmount.divide(totalAllocations.subtract(subtractDecimal));
}else{//If there is no remainder
divisibleAmount=totalAmount.divide(totalAllocations);//The divisible amount is the total amount divided by the total allocations.
}
if(remainderAmount.compareTo(BigDecimal.ZERO)>0){
System.out.println(remainderAmount);
}
//The below would be printed once for each allocation.
System.out.println(divisibleAmount);
}
}