web-dev-qa-db-fra.com

Comment arrondir 0,745 à 0,75 en utilisant BigDecimal.ROUND_HALF_UP?

J'ai essayé ce qui suit,

   double doubleVal = 1.745;
   double doubleVal1 = 0.745;
   BigDecimal bdTest = new BigDecimal(  doubleVal);
   BigDecimal bdTest1 = new BigDecimal(  doubleVal1 );
   bdTest = bdTest.setScale(2, BigDecimal.ROUND_HALF_UP);
   bdTest1 = bdTest1.setScale(2, BigDecimal.ROUND_HALF_UP);
   System.out.println("bdTest:"+bdTest); //1.75
   System.out.println("bdTest1:"+bdTest1);//0.74    problemmmm ????????????  

mais obtenu des résultats étranges. Pourquoi?

43
aliplane

Ne construisez jamais BigDecimals à partir de flottants ou de doubles. Construisez-les à partir d'ints ou de chaînes. flotte et double la précision perdue.

Ce code fonctionne comme prévu (je viens de changer le type de double en String):

public static void main(String[] args) {
  String doubleVal = "1.745";
  String doubleVal1 = "0.745";
  BigDecimal bdTest = new BigDecimal(  doubleVal);
  BigDecimal bdTest1 = new BigDecimal(  doubleVal1 );
  bdTest = bdTest.setScale(2, BigDecimal.ROUND_HALF_UP);
  bdTest1 = bdTest1.setScale(2, BigDecimal.ROUND_HALF_UP);
  System.out.println("bdTest:"+bdTest); //1.75
  System.out.println("bdTest1:"+bdTest1);//0.75, no problem
}
85
Augusto
double doubleVal = 1.745;
double doubleVal1 = 0.745;
System.out.println(new BigDecimal(doubleVal));
System.out.println(new BigDecimal(doubleVal1));

les sorties:

1.74500000000000010658141036401502788066864013671875
0.74499999999999999555910790149937383830547332763671875

Ce qui montre la valeur réelle des deux doubles et explique le résultat obtenu. Comme l'ont fait remarquer d'autres personnes, n'utilisez pas le constructeur double (à l'exception du cas spécifique dans lequel vous souhaitez voir la valeur réelle d'un double).

En savoir plus sur la double précision:

11
assylias

Utilisez BigDecimal.valueOf(double d) au lieu de new BigDecimal(double d). Le dernier a des erreurs de précision par float et double.

10
admoca60

Cela vous donnera peut-être un indice sur ce qui ne va pas.

import Java.math.BigDecimal;

public class Main {
    public static void main(String[] args) {
        BigDecimal bdTest = new BigDecimal(0.745);
        BigDecimal bdTest1 = new BigDecimal("0.745");
        bdTest = bdTest.setScale(2, BigDecimal.ROUND_HALF_UP);
        bdTest1 = bdTest1.setScale(2, BigDecimal.ROUND_HALF_UP);
        System.out.println("bdTest:" + bdTest);
        System.out.println("bdTest1:" + bdTest1); 
    }
}

Le problème est que votre entrée (un double x=0.745;) Ne peut pas représenter 0,745 exactement. En fait, il enregistre une valeur légèrement inférieure. Pour BigDecimals, il est déjà inférieur à 0,745, donc il est arrondi ...

Essayez de ne pas utiliser les constructeurs BigDecimal(double/float).

2
brimborium

Pour votre intérêt, faire de même avec double

double doubleVal = 1.745;
double doubleVal2 = 0.745;
doubleVal = Math.round(doubleVal * 100 + 0.005) / 100.0;
doubleVal2 = Math.round(doubleVal2 * 100 + 0.005) / 100.0;
System.out.println("bdTest: " + doubleVal); //1.75
System.out.println("bdTest1: " + doubleVal2);//0.75

ou juste

double doubleVal = 1.745;
double doubleVal2 = 0.745;
System.out.printf("bdTest: %.2f%n",  doubleVal);
System.out.printf("bdTest1: %.2f%n",  doubleVal2);

les deux imprimer

bdTest: 1.75
bdTest1: 0.75

Je préfère garder le code aussi simple que possible. ;)

Comme le note @mshutov, vous devez ajouter un peu plus pour vous assurer qu'une demi-valeur est toujours arrondie. C'est parce que des nombres comme 265.335 sont un peu moins qu’ils n’apparaissent.

2
Peter Lawrey