valor valiosas vale una monedas moneda dolar cuanto centavos bufalo americanos java rounding bigdecimal

java - valiosas - redondea BigDecimal a los 5 centavos más cercanos



monedas de 5 centavos valiosas (10)

Estoy tratando de averiguar cómo redondear una cantidad monetaria hacia arriba a los 5 centavos más cercanos. A continuación se muestran mis resultados esperados

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

Necesito que el resultado tenga una precisión de 2 (como se muestra arriba).

Actualizar

Siguiendo los consejos a continuación, lo mejor que pude hacer es esto.

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)

No estoy convencido de que sea 100% kosher; me preocupa que la precisión se pierda al convertir desde y hacia el doble. Sin embargo, es lo mejor que he encontrado hasta ahora y parece funcionar.


Aquí hay un par de métodos muy simples en c # que escribí para siempre redondear hacia arriba o hacia abajo a cualquier valor pasado.

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


En Scala hice lo siguiente (Java abajo)

import scala.math.BigDecimal.RoundingMode def toFive( v: BigDecimal, digits: Int, roundType: RoundingMode.Value= RoundingMode.HALF_UP ):BigDecimal = BigDecimal((2*v).setScale(digits-1, roundType).toString)/2

Y en java

import java.math.BigDecimal; import java.math.RoundingMode; public static BigDecimal toFive(BigDecimal v){ return new BigDecimal("2").multiply(v).setScale(1, RoundingMode.HALF_UP).divide(new BigDecimal("2")); }


Escribí esto en Java hace unos años: 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); }


Intentaría multiplicar por 20, redondeando al entero más cercano, luego dividiendo por 20. Es un truco, pero debería darte la respuesta correcta.


Para que pase esta prueba:

assertEquals(bd("1.00"), round(bd("1.00"))); assertEquals(bd("1.00"), round(bd("1.01"))); assertEquals(bd("1.00"), round(bd("1.02"))); assertEquals(bd("1.00"), round(bd("1.024"))); assertEquals(bd("1.05"), round(bd("1.025"))); assertEquals(bd("1.05"), round(bd("1.026"))); assertEquals(bd("1.05"), round(bd("1.049"))); assertEquals(bd("-1.00"), round(bd("-1.00"))); assertEquals(bd("-1.00"), round(bd("-1.01"))); assertEquals(bd("-1.00"), round(bd("-1.02"))); assertEquals(bd("-1.00"), round(bd("-1.024"))); assertEquals(bd("-1.00"), round(bd("-1.0245"))); assertEquals(bd("-1.05"), round(bd("-1.025"))); assertEquals(bd("-1.05"), round(bd("-1.026"))); assertEquals(bd("-1.05"), round(bd("-1.049")));

Cambie ROUND_UP en ROUND_HALF_UP :

private static final BigDecimal INCREMENT_INVERTED = new BigDecimal("20"); public BigDecimal round(BigDecimal toRound) { BigDecimal divided = toRound.multiply(INCREMENT_INVERTED) .setScale(0, BigDecimal.ROUND_HALF_UP); BigDecimal result = divided.divide(INCREMENT_INVERTED) .setScale(2, BigDecimal.ROUND_HALF_UP); return result; }


Puedes usar el doble simple para hacer esto.

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

EDITAR: para números negativos necesitas restar 0.5


Según su edición, otra posible solución sería:

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

Esto tiene la ventaja de que se garantiza que no perderá precisión, aunque podría ser más lento, por supuesto ...

Y el registro de prueba de 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


Tom tiene la idea correcta, pero necesita usar los métodos BigDecimal, ya que aparentemente está usando BigDecimal porque sus valores no son susceptibles de un tipo de datos primitivo. Algo como:

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


Usando BigDecimal sin ningún doble (mejorado en la respuesta de 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; } }

El modo de redondeo es, por ejemplo, RoundingMode.HALF_UP . Para sus ejemplos, realmente desea RoundingMode.UP ( bd es un ayudante que solo devuelve 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));

También tenga en cuenta que hay un error en su último ejemplo (redondeo 1.900001 a 1.10).


public static BigDecimal roundTo5Cents(BigDecimal amount) { amount = amount.multiply(new BigDecimal("2")); amount = amount.setScale(1, RoundingMode.HALF_UP); // preferred scale after rounding to 5 cents: 2 decimal places amount = amount.divide(new BigDecimal("2"), 2, RoundingMode.HALF_UP); return amount; }

Tenga en cuenta que esta es básicamente la misma respuesta que la de John''s .