1
votes

Est-ce le comportement correct pour arrondir avec BigDecimals?

J'essaye d'arrondir BigDecimals comme ceci: 5.46597 -> 5.46, je pensais que le code ci-dessous le faisait pour moi, mais pas.

Je l'ai essayé avec BigDecimal.round et BigDecimal.setScale.

BigDecimal bD = new BigDecimal(5.46597); // whole number: 5.4659700000000004393996277940459549427032470703125 
bD.setScale(2, RoundingMode.HALF_DOWN); // 5.47
bD.round(new MathContext(3, RoundingMode.HALF_DOWN)); // 5.47

Cela ne devrait pas être 5.46, ou qu'est-ce que j'ai mal compris?

p>


4 commentaires

Si vous construisez un BigDecimal à partir d'un littéral à virgule flottante double précision, la valeur du BigDecimal ne correspondra pas exactement au nombre décimal avec lequel vous avez commencé. Si vous utilisez new BigDecimal ("5.46597") (notez les guillemets), cela vous donne-t-il le résultat que vous attendez?


Essayez plutôt d'utiliser le constructeur String: BigDecimal bD = new BigDecimal ("5.46597");


Je pense que le problème est que vous supposez à tort que seul le chiffre significatif suivant est utilisé pour l'arrondissement. Ce n'est pas le cas, tout le reste est pris en compte. @LuiggiMendoza Ce n'est pas le problème, cela produira le même résultat.


En d'autres termes: la réponse est oui , c'est un comportement correct pour l'arrondissement. Mais vous voulez évidemment un comportement étrange, incorrect à tous égards.


3 Réponses :



11
votes

HALF_DOWN arrondit uniquement lorsque la valeur réelle est exactement à mi-chemin entre les deux valeurs arrondies possibles. C'est à dire. 5.46500 -> 5.46. D'autre part 5.4650000001 -> 5.47 car c'est plus proche de 5.47 que 5.46.

Peut-être que vous recherchez RoundingMode.DOWN , qui arrondit toujours vers le bas.


7 commentaires

non, je dois calculer l'arrondi avec un seul chiffre, donc toujours vers le bas n'est pas bon pour nous. Je vais probablement réduire les chiffres inutiles alors comme: 5.46597 => 5.465 => 5.46. Merci beaucoup!


@ BalázsSipos: ce que vous décrivez est en BAS, cependant. Il tronque (pour les valeurs positives), tout comme vous le faites manuellement.


oui, mais il sera toujours arrondi alors. Vous voyez que le système que nous devons imiter un peu est arrondi comme ceci: 5.46697 => 5.47, 5.46597 => 5.46, 5.46497 => 5.46, lors de la mise à l'échelle à deux. Donc, il ne se soucie que de ce chiffre après les chiffres dont j'ai besoin.


Mais vous avez raison, ce sera ce dont j'ai besoin: bD.setScale (3, RoundingMode.DOWN) .setScale (2, RoundingMode.HALF_DOWN)


@ BalázsSipos, il semble que vous essayez d'émuler un système d'arrondi incorrect en arrondissant également de manière incorrecte dans le nouveau système. Il serait étrange qu'une exigence utilisateur réelle soit comme ça.


@ Balázs est qu'il y a une fonction tronquer dans la bibliothèque, puis utilisez-la pour couper tous les chiffres sauf les trois premiers, puis arrondissez à 2 chiffres inférieurs.


@KlitosKyriacou Ce n'est pas un nouveau système, nous avons juste besoin des mêmes résultats pour comparer. Mais NVM, merci pour les réponses! :)



2
votes

Premièrement: en utilisant le constructeur avec une valeur double, introduit immédiatement l'erreur d'approximation de chaque virgule flottante.

En utilisant

BigDecimal bD = new BigDecimal("5.46597");
bD = bD.setScale(2, RoundingMode.HALF_DOWN); // 5.47

BigDecimal bD = new BigDecimal("5.46500");
bD = bD.setScale(2, RoundingMode.HALF_DOWN); // 5.46

on obtient un nombre exact à virgule fixe avec 5 décimales.

HALF_DOWN arrondit à .500000 ... pas de fraction de plus, juste la bordure 5er.

L'arrondi logique se produira à son entier le plus proche, au-dessus de la moitié sera arrondi, au-dessous de la moitié sera arrondi vers le bas. Sur la moitié exacte , la norme mathématique internationale dit: arrondissez vers le haut, mais logiquement (à la même distance), cela peut être: HALF_UP ou HALF_DOWN. Comme l'effet seulement concerne la moitié exacte, les tests ne doivent pas être effectués avec un double constructeur, qui donne probablement une valeur un tout petit peu au-dessus ou en dessous de la moitié exacte.

Vous avez également oublié le devoir.


0 commentaires