2008-08-11 24 views
42

Récemment, j'ai essayé de comprendre l'utilisation de java.math.MathContext mais j'ai échoué à comprendre correctement. Est-il utilisé pour arrondir java.math.BigDecimal, si oui, pourquoi ne pas arrondir les chiffres décimaux, mais même la partie mentissa. De docs API, j'ai appris qu'il suit la norme spécifiée dans les spécifications ANSI X3.274-1996 et ANSI X3.274-1996/AM 1-2000 mais je ne les ai pas eu à lire en ligne.Utilisation de java.math.MathContext

Faites-moi savoir si vous avez la moindre idée à ce sujet.

Répondre

35

@jatan

Merci pour votre réponse. Ca a du sens. Pouvez-vous s'il vous plaît m'expliquer MathContext dans le contexte de la méthode BigDecimal # round.

Il n'y a rien de spécial par rapport à BigDecimal.round() toute autre méthode BigDecimal. Dans tous les cas, le MathContext spécifie le nombre de chiffres significatifs et la technique d'arrondi. Fondamentalement, il y a deux parties de chaque MathContext. Il y a une précision, et il y a aussi un RoundingMode.

La précision spécifie à nouveau le nombre de chiffres significatifs. Donc, si vous spécifiez 123 comme un nombre et que vous demandez 2 chiffres significatifs, vous obtiendrez 120. Il pourrait être plus clair si vous pensez en termes de notation scientifique.

123 serait 1.23e2 en notation scientifique. Si vous ne gardez que 2 chiffres significatifs, vous obtenez 1.2e2 ou 120. En réduisant le nombre de chiffres significatifs, nous réduisons la précision avec laquelle nous pouvons spécifier un nombre.

La partie RoundingMode spécifie comment nous devrions gérer la perte de précision. Pour réutiliser l'exemple, si vous utilisez 123 comme numéro et que vous demandez 2 chiffres significatifs, vous avez réduit votre précision. Avec un RoundingMode de HALF_UP (le mode par défaut), 123 deviendra 120. Avec un RoundingMode de CEILING, vous obtiendrez 130.

Par exemple:

System.out.println(new BigDecimal("123.4", 
        new MathContext(4,RoundingMode.HALF_UP))); 
System.out.println(new BigDecimal("123.4", 
        new MathContext(2,RoundingMode.HALF_UP))); 
System.out.println(new BigDecimal("123.4", 
        new MathContext(2,RoundingMode.CEILING))); 
System.out.println(new BigDecimal("123.4", 
        new MathContext(1,RoundingMode.CEILING))); 

Sorties:

123.4 
1.2E+2 
1.3E+2 
2E+2 

Vous pouvez voir que les deux la précision et le mode d'arrondi affectent la sortie.

+0

Existe-t-il un moyen de formater '123.4' en utilisant 2 chiffres significatifs dans une chaîne comme' 120'? C'est 2 chiffres significatifs (comme le '1.2E2') parce que les zéros de fin ne sont pas classiquement inclus dans la récupération des chiffres significatifs à moins qu'il y ait une décimale finale. Et pour mes besoins, si le nombre à mettre en forme était '103,4', je m'en fiche que vous ne puissiez pas dire qu'il y a 2 sig figs dans le résultat' 100' qui en résulte. Je veux juste un affichage plus simple/plus propre des nombres. – hepcat72

4

Si je vous comprends bien, il semble que vous attendiez que MathContext contrôle le nombre de chiffres à conserver après la virgule décimale. Ce n'est pas ce que c'est. Il spécifie le nombre de chiffres à conserver, total. Donc, si vous spécifiez que vous voulez 3 chiffres significatifs, c'est tout ce que vous obtiendrez.

Par exemple, ceci:

System.out.println(new BigDecimal("1234567890.123456789", 
        new MathContext(20))); 

System.out.println(new BigDecimal("1234567890.123456789", 
        new MathContext(10))); 

System.out.println(new BigDecimal("1234567890.123456789", 
        new MathContext(5))); 

Affichera:

1234567890.123456789 
1234567890 
1.2346E+9 
+1

Merci. Comment choisir combien de chiffres conserver après la virgule? – Drew

+1

Ce n'est pas vraiment une question pour BigDecimal. Avec BigDecimal, vous devriez plutôt spécifier le nombre de chiffres significatifs. Combien de chiffres après la virgule décimale doit être déterminé lors du formatage pour l'affichage. Vous pouvez contrôler cela avec String.format() ou DecimalFormat.format(). –

+0

@Drew Je pense que vous pouvez utiliser [BigDecimal.setScale] (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/math/BigDecimal.java# Méthode BigDecimal.setScale% 28int% 2Cjava.math.RoundingMode% 29). Le premier paramètre (échelle) spécifie combien de nombres vous voulez conserver après la virgule décimale, et le second paramètre (roundingMode) spécifie le comportement d'arrondi que vous voulez. –

4

Ce n'est pas pour le plaisir. En fait, j'ai trouvé un exemple en ligne, qui a déclaré l'utilisation de MathContext pour arrondir les montants/numéros stockés dans BigDecimal.

Par exemple,

Si MathContext est configuré pour avoir precision = 2 et rounding mode = ROUND_HALF_EVEN

BigDecimal Number = 0.5294, est arrondie à 0,53

Je pensais que c'est une technique plus récente et utilisé pour but d'arrondi. Cependant, il a tourné au cauchemar parce qu'il a commencé à arrondir même une partie du nombre de mentissa.

Par exemple,

Number = 1.5294 est arrondi à 1.5

Number = 10.5294 est arrondi à 10

Number = 101.5294 est arrondi à 100

.... et ainsi de suite

donc ce n'est pas le comportement Je m'attendais à arrondir (précision = 2).

Il semble y avoir une certaine logique parce que, d'après le modèle, je peux dire qu'il faut d'abord deux chiffres (comme la précision est 2) de nombre, puis ajoute 0 jusqu'à la non. des chiffres deviennent même que le montant non arrondi (caisse de l'exemple 101,5294 ...)

+1

donc pouvez-vous suggérer pour la solution aussi bien? –

52

Pour arrondir uniquement la partie fractionnaire d'un BigDecimal, consultez la méthode BigDecimal.setScale(int newScale, int roundingMode).

E.g. pour changer un numéro à trois chiffres après la virgule à un avec deux chiffres, et arrondi vers le haut:

BigDecimal original = new BigDecimal("1.235"); 
BigDecimal scaled = original.setScale(2, BigDecimal.ROUND_HALF_UP); 

Le résultat de ceci est une BigDecimal avec la valeur 1,24 (en raison de l'arrondi règle)

+15

C'est la réponse que les gens veulent, en travaillant avec des nombres décimaux fixes et en gardant un nombre fixe de décimales. Je ne sais pas pourquoi Sun a bousillé une précision de style à virgule flottante ici, mais c'est ce que MathContext est. –

9

J'ajouterais ici, quelques exemples. Je ne les ai pas trouvés dans les réponses précédentes, mais je les trouve utiles pour ceux qui peuvent induire en erreur chiffres significatifs avec le nombre de décimales. Supposons que nous avons un tel contexte:

MathContext MATH_CTX = new MathContext(3, RoundingMode.HALF_UP); 

Pour ce code:

BigDecimal d1 = new BigDecimal(1234.4, MATH_CTX); 
System.out.println(d1); 

il est parfaitement clair que le résultat est 1.23E+3 comme gars dit ci-dessus. Les premiers chiffres significatifs sont 123 ...

Mais que dans ce cas:

BigDecimal d2 = new BigDecimal(0.000000454770054, MATH_CTX); 
System.out.println(d2); 

votre numéro ne sera pas arrondi à 3 places après la virgule - pour quelqu'un, il peut être pas intuitif et intéressant à souligner. Au lieu de cela, il sera arrondi aux premiers 3 chiffres significatifs, qui dans ce cas sont "4 5 4". Donc, au-dessus du code, les résultats sont 4.55E-7 et non 0.000 comme on pouvait s'y attendre.

exemples similaires:

BigDecimal d3 = new BigDecimal(0.001000045477, MATH_CTX); 
System.out.println(d3); // 0.00100 

BigDecimal d4 = new BigDecimal(0.200000477, MATH_CTX); 
System.out.println(d4); // 0.200 

BigDecimal d5 = new BigDecimal(0.000000004, MATH_CTX); 
    System.out.println(d5); //4.00E-9 

J'espère que cet exemple évident, mais pertinent serait utile ...