Java 用不均匀小数进行大十进制除法

Java 用不均匀小数进行大十进制除法,java,bigdecimal,Java,Bigdecimal,我正试图在一个程序的工作与多个大十进制计算必要的工作。我很困惑,因为BigDecimal没有按照我所希望的方式合作。让我解释一下我需要它做什么: 首先,它需要一个小数点后两位的货币金额。然后是“分配”,基本上就是该金额将通过多少账户分摊 程序现在应该在两个帐户之间分配金额。当然,在某些情况下,金额不能平均分配,例如3.33美元在两个账户之间分配。在这种情况下,您必须有一个额外的美分分配或四舍五入的数字。四舍五入不是一种选择,每一分钱都必须考虑在内。以下是我到目前为止的情况: totalAlloc

我正试图在一个程序的工作与多个大十进制计算必要的工作。我很困惑,因为BigDecimal没有按照我所希望的方式合作。让我解释一下我需要它做什么:

首先,它需要一个小数点后两位的货币金额。然后是“分配”,基本上就是该金额将通过多少账户分摊

程序现在应该在两个帐户之间分配金额。当然,在某些情况下,金额不能平均分配,例如3.33美元在两个账户之间分配。在这种情况下,您必须有一个额外的美分分配或四舍五入的数字。四舍五入不是一种选择,每一分钱都必须考虑在内。以下是我到目前为止的情况:

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。然后我有一个循环,它将写入一些信息,包括dividedLocationAmount。假设总数是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美元。(因为这是剩余的部分)。我该怎么办

我通过自己的反复试验终于找到了这个问题的解决办法。结果证明,对我来说,关键是先取出余数,然后进行除法

因为我知道我想根据情况自动将大小数分成三部分,我就是这样做的

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

}
当然,在某些情况下,数量不能平均分配, 例如,3.33美元分为两个账户。那样的话,你必须 要么分配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);
如果总金额为10.51美元,并且有3个 拨款。实际上,我想要的是两次分配 5.25美元,第三次拨款为0.01美元。(因为这是 余数)。我该怎么办

现在这与上面所说的不同,你可以有3.5,3.5和3.51


但是,如果您希望单独使用0.01,则更改上面的代码分配-1&将余数设置为最后一次分配。因此,第2次分配为5.25,第3次分配为0.01,希望这有帮助。

我该怎么做?清楚地写下您的需求/案例,并将其分为步骤,这将有助于所有人(包括您)更好地理解它并开始编码。没有通读全文,没有发现什么令人困惑的地方。@NayanWadekar您应该学会从写得不好的文本中提取重要信息:)这里的两条建议是:a)阅读Java中的会计惯例。如果你没有小数点,BigDecimal不是一个好办法。b) 请继续阅读,错误就在堆栈跟踪中(它还将指向Javadoc中的相关位置)@Ordous讽刺的是,即使在阅读了“写得很糟糕的文本”之后,您也没有回答&建议我。我可以,但我不想,干杯。谢谢你的建议,但我不明白问题是如何不清楚的?我想知道一个BigDecimal可以被另一个BigDecimal整除多少次,然后把余数放在它自己的变量中?到底有什么不清楚的?你想用RoundingMode.FLOOR进行分割。我还没有机会测试它,但它看起来不错。在我发布了这个答案之后,我发现一些数字仍然给我带来了异常:线程“main”java.lang中的异常。算术异常:非终止十进制扩展;没有可精确表示的十进制结果。在mathtest.mathtest.main(mathtest.java:34)的java.math.BigDecimal.divide(未知源代码)中,我希望我不会遇到你的问题。谢谢。为了避免“非终止十进制扩展”错误,您必须使用指定精度或MathContext的divide()函数。
ACTUAL AVERAGE 1.6649999618530273
ROUNDED VALUE: 1.66
Allocation :1 = 1.66
Allocation :2 = 1.67 //-- EXTRA CENT