La classe BigDecimal
a quelques méthodes utiles pour garantir une conversion sans perte:
byteValueExact()
shortValueExact()
intValueExact()
longValueExact()
Cependant, les méthodes floatValueExact()
et doubleValueExact()
n'existent pas.
J'ai lu le code source d'OpenJDK pour les méthodes floatValue()
et doubleValue()
. Les deux semblent se replier sur Float.parseFloat()
et Double.parseDouble()
, respectivement, ce qui peut retourner l'infini positif ou négatif. Par exemple, l'analyse d'une chaîne de 10 000 9 renvoie un infini positif. Si je comprends bien, BigDecimal
n'a pas un concept interne de l'infini. En outre, l'analyse d'une chaîne de 100 9 comme double
donne 1.0E100
, ce qui n'est pas l'infini, mais perd en précision.
Qu'est-ce qu'une mise en œuvre raisonnable floatValueExact()
et doubleValueExact()
?
Je pensais à une double
solution en combinant BigDecimal.doubleValue()
, BigDecial.toString()
, Double.parseDouble(String)
et Double.toString(double)
, mais il semble en désordre. Je veux demander ici car il peut (doit!) Y avoir une solution plus simple.
Pour être clair, je n'ai pas besoin d'une solution performante.
la source
Réponses:
En lisant les documents , tout ce qu'il fait avec les
numTypeValueExact
variantes est de vérifier l'existence d'une partie fraction ou si la valeur est trop grande pour le type numérique et de lever des exceptions.Comme pour
floatValue()
etdoubleValue()
, une vérification de débordement similaire est en cours, mais au lieu de lever une exception, elle renvoie à la placeDouble.POSITIVE_INFINITY
ouDouble.NEGATIVE_INFINITY
pour les doubles etFloat.POSITIVE_INFINITY
ouFloat.NEGATIVE_INFINITY
pour les flottants.Par conséquent, l'implémentation la plus raisonnable (et la plus simple) des
exact
méthodes pour float et double, devrait simplement vérifier si la conversion renvoiePOSITIVE_INFINITY
ouNEGATIVE_INFINITY
.De plus , rappelez-vous que cela a
BigDecimal
été conçu pour gérer le manque de précision qui vient de l'utilisationfloat
oudouble
pour les grands irrationnels, par conséquent, comme l'a commenté @JB Nizet , une autre vérification que vous pouvez ajouter à ce qui précède serait de convertir ou de revenir pour voir si vous obtenez toujours la même valeur. Cela devrait prouver que la conversion était correcte.double
float
BigDecimal
Voici à quoi ressemblerait une telle méthode
floatValueExact()
:L'utilisation de
compareTo
au lieu deequals
ci-dessus est intentionnelle afin de ne pas devenir trop stricte avec les contrôles.equals
n'évaluera la valeur true que lorsque les deuxBigDecimal
objets ont la même valeur et la même échelle (taille de la partie fractionnaire de la décimale), tandis que cette valeurcompareTo
sera négligée lorsqu'elle n'aura pas d'importance. Par exemple2.0
vs2.00
.la source
Float.isFinite()
ouFloat.isInfinite()
, mais cela est facultatif.:)
123.456f
. Je suppose que cela est dû à une taille différente de significande (mantisse) entre float 32 bits et double 64 bits. Dans votre code ci - dessus, pour obtenir de meilleurs résultats avec:if (new BigDecimal(result, MathContext.DECIMAL32).equals(decimal)) {
. Est-ce un changement raisonnable ... ou manque-t-il un autre cas de coin de valeurs à virgule flottante?123.456f
est conceptuellement le même que votre exemple 1.0E100. Il me semble que si vous devez vérifier que la conversion de BigDecimal -> virgule flottante binaire est exacte, alors ce besoin est le problème; c'est-à-dire que la conversion ne doit pas être envisagée.