J'ai un XSD qui me demande d'utiliser un BigDecimal pour une lat/lon. Actuellement, je dispose de la lat/lon sous forme de doubles, et je les convertis en BigDecimal, mais je ne suis tenu d'utiliser qu'une précision d'environ 12 positions. Je n'ai pas réussi à trouver comment régler cela. Quelqu'un peut-il m'aider ?
Réponses
Trop de publicités?Vous pouvez utiliser setScale() par exemple
double d = ...
BigDecimal db = new BigDecimal(d).setScale(12, BigDecimal.ROUND_HALF_UP);
Le titre de la question porte sur la précision. BigDecimal fait la distinction entre échelle et précision. L'échelle est le nombre de décimales. Vous pouvez considérer la précision comme le nombre de chiffres significatifs également connus sous le nom de chiffres significatifs.
Quelques exemples en Clojure.
(.scale 0.00123M) ; 5
(.precision 0.00123M) ; 3
(En Clojure, le M
désigne un littéral BigDecimal. Vous pouvez traduire le Clojure en Java si vous le souhaitez, mais je trouve qu'il est plus compact que le Java).
Vous pouvez facilement augmenter l'échelle :
(.setScale 0.00123M 7) ; 0.0012300M
Mais vous ne pouvez pas diminuer la balance de la même manière :
(.setScale 0.00123M 3) ; ArithmeticException Rounding necessary
Vous devrez également passer un mode d'arrondi :
(.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.
Il est donc facile de changer l'échelle. Mais qu'en est-il de la précision ? Ce n'est pas aussi facile que vous pourriez l'espérer !
Il est facile de diminuer la précision :
(.round 3.14159M (java.math.MathContext. 3)) ; 3.14M
Mais il n'est pas évident de savoir comment augmentation de la précision :
(.round 3.14159M (java.math.MathContext. 7)) ; 3.14159M (unexpected)
Pour les sceptiques, c'est pas il s'agit simplement de ne pas afficher les zéros de fin de ligne :
(.precision (.round 3.14159M (java.math.MathContext. 7))) ; 6
; (same as above, still unexpected)
Pour information, Clojure est prudent avec les zéros de fin de ligne et sera les montrer :
4.0000M ; 4.0000M
(.precision 4.0000M) ; 5
Retour sur la piste... Vous pouvez essayer d'utiliser un BigDecimal mais il ne définit pas la précision au-delà du nombre de chiffres que vous spécifiez :
(BigDecimal. "3" (java.math.MathContext. 5)) ; 3M
(BigDecimal. "3.1" (java.math.MathContext. 5)) ; 3.1M
Il n'y a donc pas de moyen rapide de modifier la précision. J'ai passé du temps à me battre contre cela en rédigeant cette question et avec un projet sur lequel je travaille. Je considère cela, au mieux, comme une API CRAZYTOWN, et au pire comme un bug. Les gens. Sérieusement ?
Donc, d'après ce que je sais, si vous voulez changer la précision, vous devez suivre ces étapes :
- Recherche de la précision actuelle.
- Recherche l'échelle actuelle.
- Calculez le changement d'échelle.
- Définir la nouvelle échelle
Ces étapes, en tant que code 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
Je sais, c'est beaucoup d'étapes juste pour changer la précision !
Pourquoi BigDecimal ne fournit-il pas déjà cela ? Ai-je oublié quelque chose ?
BigDecimal decPrec = (BigDecimal)yo.get("Avg");
decPrec = decPrec.setScale(5, RoundingMode.CEILING);
String value= String.valueOf(decPrec);
De cette façon, vous pouvez définir la précision spécifique d'un BigDecimal
.
La valeur de decPrec était 1.5726903423607562595809913132345426
qui est arrondi à 1.57267
.