BigDecimal除以小数位数不均匀

时间:2016-01-07 16:05:00

标签: java bigdecimal

我正在尝试使用必要的多个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美元。 (因为那是剩下的)。我该怎么办?

2 个答案:

答案 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);
    }

}