Arrondi à n chiffres significatifs

juancho2786 Messages postés 39 Date d'inscription mardi 5 juillet 2005 Statut Membre Dernière intervention 29 octobre 2008 - 19 nov. 2006 à 00:18
DonBanini Messages postés 1 Date d'inscription lundi 16 février 2009 Statut Membre Dernière intervention 7 avril 2009 - 7 avril 2009 à 16:14
Bonsoir , je fais une méthode qui permet d'arrondir à n chiffres significatis seulement j'ai un problème. Par exemple lorsque le nombre à arrondir est 0.000023678 et j'aimerais l'arrondire à 3 chiffres significatifs, cela devrait donné 0.0000237 et pas 2370.0 comme c'est le cas dans ma méthode. Sinon pour le reste ça marche correctement, enfin je pense...
Avez vous une idée? merci beaucoup !!
voici la code :

public static double arrondiNChiffresSignificatifs(double nombre, int n){
  char signe;
  int exposant=0;
  
  if(nombre<0)signe='-';
  else signe='+';
  nombre=Math.abs(nombre);
  while(nombre<0.1){
   nombre*=10;
   exposant++;
  }
  while(nombre>=1){
   nombre/=10;
   exposant++;   
  }
  nombre=(Math.round(nombre*Math.pow(10,n)))*Math.pow(10,exposant)/(Math.pow(10,n));
  if(signe=='-')return -nombre;
  else return nombre;
 }

4 réponses

abdouinfomiage Messages postés 80 Date d'inscription mardi 26 juillet 2005 Statut Membre Dernière intervention 3 février 2008
19 nov. 2006 à 03:41
public double round(double what, int howmuch) {
return (double)( (int)(what * Math.pow(10,howmuch) + .5) ) / Math.pow(10,howmuch);
}

System.out.println(round(1.6666666,2));
System.out.println(round(1.6666666,3));
System.out.println(round(1.6666666,0));Résultats :
}
regarde cet example et bonne chance
0
verdy_p Messages postés 202 Date d'inscription vendredi 27 janvier 2006 Statut Membre Dernière intervention 29 janvier 2019
9 avril 2008 à 03:17
abouinfoimage, ta solution est fausse et ne répond pas au problème. Il ne demande pas à arrondir un double sur N décimales, mais à N chiffres significatifs (à priori N < 17 car au delà, il n'y a plus aucun chiffre significatif et plus rien à arrondir dans un double) ; relis sa question, il a été très clair dans son exemple!

Son problème est moins simple qu'il y parait, car il faut faire attention à ne pas déborder en capacité pour des valeurs limites, ce qui peut arriver si on multiplie puis divise.

L’algo doit donc:
 * trouver k, le logarithme de base 10 (arrondi à l'entier inférieur) du nombre x pour pouvoir le ramener à un intervalle entre 0,1 compris et 1,0 non compris (si on le divisait par 10^k); k est petit (à cause de  la capacité maximale des "double", k sera entre -308 et 308 si je me souviens bien, pour les valeurs normales) et tient dans un entier;
* en ajoutant à cet entier le nombre de chiffre significatifs demandés N, on a un nombre dans l'intervalle entre 10^(N-1) compris et 10^N non compris afin de prendre l'entier arrondi; attention: pour N=16, 10^16 ne tient pas dans un "int", on doit utiliser Math.floor() (du moins tant que le nombre est positif.
* après l'arrondi, il reste à ramener à l'ordre de grandeur d'origine.
* on doit compléter en traitant spécialement l'arrondi de 0.0.

Ma solution est donc plutôt:






public static double arrondiNChiffresSignificatifs(final double x, final int n){
    if (n < 1)
        throw new BadArgumentException("n < 1");
    if (n > 17)
        return x;
    if (x == 0)
        return 0;
    final double signedScale = x < 0 ?
      -Math.pow(10, Math.floor(Math.log10(-x)) - n + 1) :
       Math.pow(10, Math.floor(Math.log10(x)) - n + 1);
    return Math.floor(x / signedScale + 0.5) * signedScale;
}

Note: l'arrondi est sans doute approximatif pour les valeurs dénormales très proches de 0, c'est à dire k <= -308, là où le logarithme de base 10 est aussi approximatif.
0
verdy_p Messages postés 202 Date d'inscription vendredi 27 janvier 2006 Statut Membre Dernière intervention 29 janvier 2019
9 avril 2008 à 03:28
pour l'arrondi à l'entier le plus proche j'ai utilisé Math.floor(x+0.5) dans l'instruction return; si tu veux l'arrondi IEEE à l'entier pair le plus proche quand on est juste au milieu de deux entiers, on peut aussi utiliser Math.round(x)... Cela ne change pas énormément les choses.
L'autre solution est d'utiliser la conversion via une chaine et un format, puis la conversion inverse, mais c'est bien plus lourd car Java gère le formatage en fonction d'une locale, et effectue des tas d'autres fonctions en interne pour gérer les formateurs de nombres, et réanalyser la chaîne.
0
DonBanini Messages postés 1 Date d'inscription lundi 16 février 2009 Statut Membre Dernière intervention 7 avril 2009
7 avril 2009 à 16:14
Whoa, merci (1 ans après....), çà m'as aussi vachement aidé, même si j'ai pas très bien suivit de raisonnement.... :(
0
Rejoignez-nous