java bigdecimal floating-point-precision

java - Establecer precisión específica de un BigDecimal



jpa bigdecimal (4)

Tengo un XSD que requiere que use un BigDecimal para un lat / lon. Actualmente tengo el lat / lon como dobles y los convierto en BigDecimal, pero solo debo usar unos 12 lugares de precisión. No he podido averiguar cómo configurar eso. Puede alguien ayudarme con esto?


El título de la pregunta pregunta acerca de la precisión. BigDecimal distingue entre escala y precisión. La escala es la cantidad de decimales. Puede pensar en la precisión como la cantidad de cifras significativas , también conocidas como dígitos significativos.

Algunos ejemplos en Clojure.

(.scale 0.00123M) ; 5 (.precision 0.00123M) ; 3

(En Clojure, The M designa un literal BigDecimal. Si lo desea, puede traducir Clojure a Java, pero creo que es más compacto que Java).

Puede aumentar fácilmente la escala:

(.setScale 0.00123M 7) ; 0.0012300M

Pero no puede disminuir la escala de la misma manera:

(.setScale 0.00123M 3) ; ArithmeticException Rounding necessary

También deberá pasar un modo de redondeo:

(.setScale 0.00123M 3 BigDecimal/ROUND_HALF_EVEN) ; ; Note: BigDecimal would prefer that you use the MathContext rounding ; constants, but I don''t have them at my fingertips right now.

Por lo tanto, es fácil cambiar la escala. ¿Pero qué hay de la precisión? ¡Esto no es tan fácil como podrías esperar!

Es fácil disminuir la precisión:

(.round 3.14159M (java.math.MathContext. 3)) ; 3.14M

Pero no es obvio cómo aumentar la precisión:

(.round 3.14159M (java.math.MathContext. 7)) ; 3.14159M (unexpected)

Para los escépticos, esto no es solo una cuestión de ceros que no se muestran:

(.precision (.round 3.14159M (java.math.MathContext. 7))) ; 6 ; (same as above, still unexpected)

FWIW, Clojure tiene cuidado con los ceros al final y les mostrará:

4.0000M ; 4.0000M (.precision 4.0000M) ; 5

Volviendo a la pista ... Puede intentar usar un constructor BigDecimal , pero no establece la precisión más allá de la cantidad de dígitos que especifique:

(BigDecimal. "3" (java.math.MathContext. 5)) ; 3M (BigDecimal. "3.1" (java.math.MathContext. 5)) ; 3.1M

Entonces, no hay una manera rápida de cambiar la precisión. He pasado tiempo luchando con esto mientras escribo esta pregunta y con un proyecto en el que estoy trabajando. Considero esto, en el mejor de los casos, una API CRAZYTOWN y, en el peor de los casos, un error. Gente. ¿Seriamente?

Entonces, lo mejor que puedo decir es que si quieres cambiar la precisión, deberás seguir estos pasos:

  1. Busque la precisión actual.
  2. Busque la escala actual.
  3. Calcule el cambio de escala.
  4. Establecer la nueva escala

Estos pasos, como código de Clojure:

(def x 0.000691M) ; the input number (def p'' 1) ; desired precision (def s'' (+ (.scale x) p'' (- (.precision x)))) ; desired new scale (.setScale x s'' BigDecimal/ROUND_HALF_EVEN) ; 0.0007M

Lo sé, ¡este es un montón de pasos solo para cambiar la precisión!

¿Por qué BigDecimal ya no proporciona esto? ¿Pasé por alto algo?


Prueba este código ...

Integer perc = 5; BigDecimal spread = BigDecimal.ZERO; BigDecimal perc = spread.setScale(perc,BigDecimal.ROUND_HALF_UP); System.out.println(perc);

Resultado: 0.00000


Puede usar setScale() ej.

double d = ... BigDecimal db = new BigDecimal(d).setScale(12, BigDecimal.ROUND_HALF_UP);


BigDecimal decPrec = (BigDecimal)yo.get("Avg"); decPrec = decPrec.setScale(5, RoundingMode.CEILING); String value= String.valueOf(decPrec);

De esta forma puede establecer la precisión específica de un BigDecimal .

El valor de decPrec fue 1.5726903423607562595809913132345426 que se redondea a 1.57267 .