1

元の合計と一致する必要があるパーセンテージから合計を計算しています。ただし、浮動小数点に対しては、合計が一致することはありません。

例。

合計パーセンテージは327.81から計算されます

四捨五入されていない金額の例

30%     98.343
20%     65.562
30%     98.343
20%     65.562
Total  327.81 

四捨五入の例

30% 98.34
20% 65.56
30% 98.34
20% 65.56
Total 327.80 

私の金額は通貨形式に四捨五入する必要がありますが、四捨五入された金額は、元の金額である327.81と等しいので327.80から1セント離れていることに気付くでしょう。

最後に、これら2つの金額が互いに等しいことを検証する必要があります。これは明らかに検証されません。経営陣から、ロジックに.05の差異を追加するように言われました。互いに等しい値と比較することはできますが、分散を方程式に追加する方法がわかりません。誰かがこれを私の状態に追加する方法を理解するのを手伝ってもらえますか?

これは、それらが互いに等しいことを比較する私の現在のコードです。

if (   this.pr.getRequisitionTotal() != null 
    && this.pr.getRequisitionTotal().compareTo(lineItemTotal) != 0
    && this.reviewedAuditActions()) 
{
    this.form.recordError("Requisition total must equal line item running total.");
}
4

2 に答える 2

1

標準的な解決策は、「実際の」量と丸められたバージョンの間の累積偏差を追跡し、偏差を0.5未満に保つように丸めを調整することです。これは、BigDecimalを使用した概念の実装です。これにより、一種の言葉遣いになりますが、浮動小数点を使用する場合に固有の表現の問題を回避できます。

たとえば、RoundingAccumulatorこの動作をカプセル化するという名前のクラスを作成した場合、コードの残りの部分から厄介な詳細を隠すことができます。

    BigDecimal value = new BigDecimal("327.81");
    BigDecimal[] percents = new BigDecimal[] {
            new BigDecimal(30),
            new BigDecimal(20),
            new BigDecimal(30),
            new BigDecimal(20) };
    BigDecimal accError = BigDecimal.ZERO;
    BigDecimal maxError = new BigDecimal("0.005");
    BigDecimal adjust   = new BigDecimal("0.01");
    BigDecimal hundred  = new BigDecimal("100");
    BigDecimal total    = BigDecimal.ZERO;
    for (BigDecimal pct : percents)
    {
        BigDecimal unrounded    = value.multiply(pct).divide(hundred); 
        BigDecimal rounded      = unrounded.setScale(2,RoundingMode.HALF_EVEN);
        BigDecimal error        = rounded.subtract(unrounded);
        BigDecimal correction   = BigDecimal.ZERO;
        accError = accError.add(error);
        if (accError.abs().compareTo(maxError) > 0)
            correction = accError.signum() > 0 ? adjust.negate() : adjust;
        rounded = rounded.add(correction);
        accError = accError.add(correction);
        System.out.println(unrounded.toString() + " " + rounded.toString() + " " + error.toString() + " " + accError.toString() + " " + correction.toString());

        total = total.add(rounded);
    }
    System.out.println("Total is " + total.toString());
}
于 2012-10-24T19:08:30.693 に答える
1
final double EPSILON = 0.05;
double a = 0.5;
double b = 0.51;
if (Math.abs(a-b) <= EPSILON){
// match
}
else{
// no match
}
于 2012-10-24T19:16:59.757 に答える