Comment vérifier si un double a au plus n décimales?
Actuellement, j'ai cette méthode:
static boolean checkDecimalPlaces(double d, int decimalPlaces){
if (d==0) return true;
double multiplier = Math.pow(10, decimalPlaces);
double check = d * multiplier;
check = Math.round(check);
check = check/multiplier;
return (d==check);
}
Mais cette méthode n'est pas pour checkDecmialPlaces(649632196443.4279, 4)
probablement parce que je fais de la base de 10 les mathématiques sur une base de 2 numéro.
Alors, comment cela peut-il vérifier être fait correctement?
J'ai pensé à l'obtention d'une représentation de chaîne de la valeur double, puis vérifier avec une regexp - mais que me sentais bizarre.
EDIT:
Merci pour toutes les réponses. Il y a des cas où j'ai vraiment obtenir un double et pour les cas j'ai mis en place les éléments suivants:
private static boolean checkDecimalPlaces(double d, int decimalPlaces) {
if (d == 0) return true;
final double epsilon = Math.pow(10.0, ((decimalPlaces + 1) * -1));
double multiplier = Math.pow(10, decimalPlaces);
double check = d * multiplier;
long checkLong = (long) Math.abs(check);
check = checkLong / multiplier;
double e = Math.abs(d - check);
return e < epsilon;
}
J'ai changé le round
à une troncature. Semble que le calcul fait dans round
augmente l'imprécision de trop. Au moins dans le défaut testcase.
Comme certains de vous l'ont souligné, si je pouvais obtenir la 'vraie' entrée de chaîne que je devrais utiliser BigDecimal
de vérifier et j'ai donc fait:
BigDecimal decimal = new BigDecimal(value);
BigDecimal checkDecimal = decimal.movePointRight(decimalPlaces);
return checkDecimal.scale() == 0;
La double
valeur que je reçois vient de Apache POI API qui lit les fichiers excel. J'ai fait quelques tests et constaté que, bien que l'API retourne double
valeurs numériques des cellules que je peux obtenir une représentation exacte quand j'ai immédiatement format double
avec le DecimalFormat
:
DecimalFormat decimalFormat = new DecimalFormat();
decimalFormat.setMaximumIntegerDigits(Integer.MAX_VALUE);
//don't use grouping for numeric-type cells
decimalFormat.setGroupingUsed(false);
decimalFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
value = decimalFormat.format(numericValue);
Cela fonctionne aussi pour les valeurs qui ne peuvent pas être représentés exactement dans le format binaire.
OriginalL'auteur Turismo | 2008-11-05
Vous devez vous connecter pour publier un commentaire.
Le test échoue, parce que vous avez atteint la précision de la binaire à virgule flottante représentation, qui est d'environ 16 chiffres avec IEEE754 double précision. En multipliant par 649632196443.4279 par 10000 va tronquer la représentation binaire, conduisant à des erreurs lors de l'arrondissement et en divisant par la suite, ce qui permet d'invalider le résultat de votre fonction complètement.
Pour plus de détails, voir http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
Une meilleure façon serait de vérifier si le
n+1
décimales sont en dessous d'un certain seuil. Sid - round(d)
est à moins deepsilon
(voir limite), la représentation décimale ded
n'a pas de décimales significatives. De même, si(d - round(d)) * 10^n
est à moins deepsilon
, d peut avoir au plusn
endroits importants.Utilisation Jon Skeet's
DoubleConverter
à vérifier pour le cas oùd
n'est pas assez précis pour contenir le nombre de décimales que vous recherchez.OriginalL'auteur David Schmitt
Si votre objectif est de représenter un nombre avec exactement n chiffres significatifs à droite de la virgule, BigDecimal est la classe à utiliser.
scale
peut être réglée via setScale(int)OriginalL'auteur Ken Gentle
Comme avec tous arithmétique à virgule flottante, vous ne devez pas vérifier pour l'égalité, mais plutôt que l'erreur (epsilon) est suffisamment petit.
Si vous remplacez:
avec quelque chose comme
il devrait fonctionner. De toute évidence, l'epsilon doit être sélectionné pour être assez petit comparé avec le nombre de décimales que vous êtes arrivée.
IEE 754 64 bits double seulement environ 18 chiffres de précision de toute façon donc, si vous vous levez dans les numéros de la multipliant par 1000 va entraîner un dépassement de capacité (environ 10^304), vous pouvez être certain qu'il y a zéro décimales dans la représentation.
OriginalL'auteur paxdiablo
La
double
est de type binaire, nombre à virgule flottante. Il y a toujours apparentes inexactitudes de traiter avec eux comme s'ils étaient décimale des nombres à virgule flottante. Je ne sais pas que vous aurez jamais être en mesure d'écrire fonctionner, de sorte qu'il fonctionne comme vous le souhaitez.Vous aurez probablement à revenir à la source du numéro (une chaîne de caractères d'entrée peut-être), et de garder la représentation décimale si il est important pour vous.
OriginalL'auteur Ned Batchelder
Si vous pouvez passer à BigDecimal, alors que Ken G explique, c'est ce que vous devriez être en utilisant.
Si non, alors vous avez à traiter avec une foule de questions, comme mentionné dans les autres réponses. Pour moi, vous êtes face à un nombre binaire (double) et poser une question à propos d'une représentation décimale de ce nombre; c'est à dire, que vous posez sur une Chaîne. Je pense que votre intuition est correcte.
OriginalL'auteur Glenn
Je ne suis pas sûr que ce soit vraiment faisable en général. Par exemple, combien de décimales ne
1.0e-13
? Que faire si il y a certaines erreurs d'arrondi tout en faisant de l'arithmétique et est vraiment juste0
dans le déguisement? Si, d'autre part, vous vous demandez s'il y a des non-zéro chiffres dans la première n décimales, vous pouvez faire quelque chose comme:d
avant de le tronquer pour ne pas perdre de chiffres significatifs - voir mon edit de la questionOriginalL'auteur tvanfosson
Je pense que c'est mieux
Convertir en string et d'interroger la valeur de l'exposant
OriginalL'auteur Norm Wright