Partage
  • Partager sur Facebook
  • Partager sur Twitter

Comment fonctionne la division des BigDecimal ?

Sujet résolu
    19 novembre 2010 à 11:29:26

    Voilà, je souhaite faire une division de 2 décimaux avec BigDecimal.

    Par exemple :

    BigDecimal b1 = new BigDecimal(65.456); // b1 = 65,456
    BigDecimal b2 = new BigDecimal(7.55); // b2 = 7,55
    System.out.println(b1.divide(b2));
    


    Et ceci me retourne l'erreur suivante :

    Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
    at java.math.BigDecimal.divide(Unknown Source)


    Y a-t-il une solution, en utilisant les scales par exemple ?

    PS : je précise bien sûr que pour add, subtract et multiply, il n'y a aucun souci.
    • Partager sur Facebook
    • Partager sur Twitter
      19 novembre 2010 à 11:44:42

      Pour faire un divide avec cette classe il faut toujours préciser le mode d'arrondi.

      La classe BigDecimal propose plusieurs modes d'arrondis : ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_UP, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_UNNECESSARY et ROUND_UP. C'est à toi de chosiir ce qui va le mieux.

      Dans ton cas, on pourrait avoir:
      BigDecimal b1 = new BigDecimal(65.456); // b1 = 65,456
      BigDecimal b2 = new BigDecimal(7.55); // b2 = 7,55
      System.out.println(b1.divide(b2,10,BigDecimal.ROUND_HALF_DOWN)));
      
      • Partager sur Facebook
      • Partager sur Twitter
      J'ai tous les badges d'OpenClassrooms.
        19 novembre 2010 à 14:49:45

        Citation : willard

        Pour faire un divide avec cette classe il faut toujours préciser le mode d'arrondi.

        La classe BigDecimal propose plusieurs modes d'arrondis : ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_UP, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_UNNECESSARY et ROUND_UP. C'est à toi de chosiir ce qui va le mieux.

        Dans ton cas, on pourrait avoir:

        BigDecimal b1 = new BigDecimal(65.456); // b1 = 65,456
        BigDecimal b2 = new BigDecimal(7.55); // b2 = 7,55
        System.out.println(b1.divide(b2,10,BigDecimal.ROUND_HALF_DOWN)));
        


        Ce n'est plus vrai depuis Java 1.5, on peut se passer de l'arrondi.
        Néanmoins dans ton cas, il est nécessaire.

        Cf le code de la division de bigints sans arrondi spécifié (et donc pourquoi tu as cette erreur) :
        /**
             * Returns a {@code BigDecimal} whose value is {@code (this /
             * divisor)}, and whose preferred scale is {@code (this.scale() -
             * divisor.scale())}; if the exact quotient cannot be
             * represented (because it has a non-terminating decimal
             * expansion) an {@code ArithmeticException} is thrown.
             *
             * @param  divisor value by which this {@code BigDecimal} is to be divided.
             * @throws ArithmeticException if the exact quotient does not have a
             *         terminating decimal expansion
             * @return {@code this / divisor}
             * @since 1.5
             * @author Joseph D. Darcy
             */
            public BigDecimal divide(BigDecimal divisor) {
        	/*
        	 * Handle zero cases first.
        	 */
                if (divisor.signum() == 0) {   // x/0
                    if (this.signum() == 0)    // 0/0
                        throw new ArithmeticException("Division undefined");  // NaN
                    throw new ArithmeticException("Division by zero");
        	}
        
        	// Calculate preferred scale
                int preferredScale = saturateLong((long)this.scale - divisor.scale);
                
                if (this.signum() == 0)      // 0/y
                    return (0<=preferredScale && preferredScale<ZERO_SCALED_BY.length) ? 
                        ZERO_SCALED_BY[preferredScale] :
                        BigDecimal.valueOf(0, preferredScale);
        	else {
        	    this.inflate();
        	    divisor.inflate();
        	    /*
        	     * If the quotient this/divisor has a terminating decimal
        	     * expansion, the expansion can have no more than
        	     * (a.precision() + ceil(10*b.precision)/3) digits.
        	     * Therefore, create a MathContext object with this
        	     * precision and do a divide with the UNNECESSARY rounding
        	     * mode.
        	     */
        	    MathContext mc = new MathContext( (int)Math.min(this.precision() + 
        							    (long)Math.ceil(10.0*divisor.precision()/3.0),
        							    Integer.MAX_VALUE),
        					      RoundingMode.UNNECESSARY);
        	    BigDecimal quotient;
        	    try {
        		quotient = this.divide(divisor, mc);
        	    } catch (ArithmeticException e) {
        		throw new ArithmeticException("Non-terminating decimal expansion; " + 
        					      "no exact representable decimal result.");
        	    }
        
        	    int quotientScale = quotient.scale();
        
        	    // divide(BigDecimal, mc) tries to adjust the quotient to
        	    // the desired one by removing trailing zeros; since the
        	    // exact divide method does not have an explicit digit
        	    // limit, we can add zeros too.
        	    if (preferredScale > quotientScale)
        		return quotient.setScale(preferredScale, ROUND_UNNECESSARY);
        
        	    return quotient;
        	}
            }
        
        • Partager sur Facebook
        • Partager sur Twitter
          19 novembre 2010 à 14:59:32

          Citation : SpaceFox

          Ce n'est plus vrai depuis Java 1.5, on peut se passer de l'arrondi.
          Néanmoins dans ton cas, il est nécessaire.

          Cf le code de la division de bigints sans arrondi spécifié (et donc pourquoi tu as cette erreur) :



          Dans la plus part des cas tu en auras toujours besoin, c'est plus une mesure de sécurité qu'autre chose.
          • Partager sur Facebook
          • Partager sur Twitter
          J'ai tous les badges d'OpenClassrooms.

          Comment fonctionne la division des BigDecimal ?

          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
          • Editeur
          • Markdown