20

金額を5セント単位で切り上げる方法を見つけようとしています。以下は私の期待される結果を示しています

1.03     => 1.05
1.051    => 1.10
1.05     => 1.05
1.900001 => 1.10

結果は2の精度である必要があります(上記のように)。

アップデート

以下のアドバイスに従って、私ができる最善のことはこれです

    BigDecimal amount = new BigDecimal(990.49)

    // To round to the nearest .05, multiply by 20, round to the nearest integer, then divide by 20
   def result =  new BigDecimal(Math.ceil(amount.doubleValue() * 20) / 20)
   result.setScale(2, RoundingMode.HALF_UP)

これが100%コーシャであるとは確信していません-ダブルスとの間で変換するときに精度が失われる可能性があるのではないかと心配しています。しかし、これは私がこれまでに思いついた中で最高であり、機能しているようです。

4

11 に答える 11

72

BigDecimaldouble なしで使用(marcolopes からの回答で改善):

public static BigDecimal round(BigDecimal value, BigDecimal increment,
                               RoundingMode roundingMode) {
    if (increment.signum() == 0) {
        // 0 increment does not make much sense, but prevent division by 0
        return value;
    } else {
        BigDecimal divided = value.divide(increment, 0, roundingMode);
        BigDecimal result = divided.multiply(increment);
        return result;
    }
}

丸めモードは、たとえばRoundingMode.HALF_UPです。あなたの例では、実際に必要ですRoundingMode.UP(bdは単に返すヘルパーですnew BigDecimal(input)):

assertEquals(bd("1.05"), round(bd("1.03"), bd("0.05"), RoundingMode.UP));
assertEquals(bd("1.10"), round(bd("1.051"), bd("0.05"), RoundingMode.UP));
assertEquals(bd("1.05"), round(bd("1.05"), bd("0.05"), RoundingMode.UP));
assertEquals(bd("1.95"), round(bd("1.900001"), bd("0.05"), RoundingMode.UP));

また、最後の例には間違いがあることに注意してください (1.900001 を 1.10 に丸めます)。

于 2013-05-21T08:29:26.597 に答える
11

20を掛けて、最も近い整数に丸めてから、20で割ってみます。これはハックですが、正しい答えが得られるはずです。

于 2010-01-21T03:06:00.643 に答える
8

数年前に Java でこれを書きました: https://github.com/marcolopes/dma/blob/master/org.dma.java/src/org/dma/java/math/BusinessRules.java

/**
 * Rounds the number to the nearest<br>
 * Numbers can be with or without decimals<br>
 */
public static BigDecimal round(BigDecimal value, BigDecimal rounding, RoundingMode roundingMode){

    return rounding.signum()==0 ? value :
        (value.divide(rounding,0,roundingMode)).multiply(rounding);

}


/**
 * Rounds the number to the nearest<br>
 * Numbers can be with or without decimals<br>
 * Example: 5, 10 = 10
 *<p>
 * HALF_UP<br>
 * Rounding mode to round towards "nearest neighbor" unless
 * both neighbors are equidistant, in which case round up.
 * Behaves as for RoundingMode.UP if the discarded fraction is >= 0.5;
 * otherwise, behaves as for RoundingMode.DOWN.
 * Note that this is the rounding mode commonly taught at school.
 */
public static BigDecimal roundUp(BigDecimal value, BigDecimal rounding){

    return round(value, rounding, RoundingMode.HALF_UP);

}


/**
 * Rounds the number to the nearest<br>
 * Numbers can be with or without decimals<br>
 * Example: 5, 10 = 0
 *<p>
 * HALF_DOWN<br>
 * Rounding mode to round towards "nearest neighbor" unless
 * both neighbors are equidistant, in which case round down.
 * Behaves as for RoundingMode.UP if the discarded fraction is > 0.5;
 * otherwise, behaves as for RoundingMode.DOWN.
 */
public static BigDecimal roundDown(BigDecimal value, BigDecimal rounding){

    return round(value, rounding, RoundingMode.HALF_DOWN);

}
于 2013-01-21T15:24:42.617 に答える
3

ここに、渡された値に常に切り上げまたは切り捨てを行うように記述した、c# の非常に単純なメソッドをいくつか示します。

public static Double RoundUpToNearest(Double passednumber, Double roundto)
    {

        // 105.5 up to nearest 1 = 106
        // 105.5 up to nearest 10 = 110
        // 105.5 up to nearest 7 = 112
        // 105.5 up to nearest 100 = 200
        // 105.5 up to nearest 0.2 = 105.6
        // 105.5 up to nearest 0.3 = 105.6

        //if no rounto then just pass original number back
        if (roundto == 0)
        {
            return passednumber;
        }
        else
        {
            return Math.Ceiling(passednumber / roundto) * roundto;
        }
    }
    public static Double RoundDownToNearest(Double passednumber, Double roundto)
    {

        // 105.5 down to nearest 1 = 105
        // 105.5 down to nearest 10 = 100
        // 105.5 down to nearest 7 = 105
        // 105.5 down to nearest 100 = 100
        // 105.5 down to nearest 0.2 = 105.4
        // 105.5 down to nearest 0.3 = 105.3

        //if no rounto then just pass original number back
        if (roundto == 0)
        {
            return passednumber;
        }
        else
        {
            return Math.Floor(passednumber / roundto) * roundto;
        }
    }
于 2010-11-16T19:24:48.513 に答える
0

あなたの編集に基づいて、別の可能な解決策は次のとおりです。

BigDecimal twenty = new BigDecimal(20);
BigDecimal amount = new BigDecimal(990.49)

// To round to the nearest .05, multiply by 20, round to the nearest integer, then divide by 20
BigDecimal result =  new BigDecimal(amount.multiply(twenty)
                                          .add(new BigDecimal("0.5"))
                                          .toBigInteger()).divide(twenty);

これには、もちろん遅くなる可能性がありますが、精度を失わないことが保証されるという利点があります...

そしてscalaテストログ:

scala> var twenty = new java.math.BigDecimal(20) 
twenty: java.math.BigDecimal = 20

scala> var amount = new java.math.BigDecimal("990.49");
amount: java.math.BigDecimal = 990.49

scala> new BigDecimal(amount.multiply(twenty).add(new BigDecimal("0.5")).toBigInteger()).divide(twenty)
res31: java.math.BigDecimal = 990.5
于 2010-01-23T21:09:32.837 に答える
-1

トムは正しい考えを持っていますが、値がプリミティブデータ型に対応していないため、表向きは BigDecimal を使用しているため、BigDecimal メソッドを使用する必要があります。何かのようなもの:

BigDecimal num = new BigDecimal(0.23);
BigDecimal twenty = new BigDecimal(20);
//Might want to use RoundingMode.UP instead,
//depending on desired behavior for negative values of num.
BigDecimal numTimesTwenty = num.multiply(twenty, new MathContext(0, RoundingMode.CEILING)); 
BigDecimal numRoundedUpToNearestFiveCents
  = numTimesTwenty.divide(twenty, new MathContext(2, RoundingMode.UNNECESSARY));
于 2010-01-21T03:27:44.247 に答える
-3

これを行うには、プレーンな double を使用できます。

double amount = 990.49;
double rounded = ((double) (long) (amount * 20 + 0.5)) / 20;

編集:負の数の場合、0.5を引く必要があります

于 2010-01-23T22:12:27.027 に答える