IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

pow(2, 54) et pow(2, 54) - 1 donnent le même résultat


Sujet :

C

  1. #1
    Membre confirmé Avatar de YuGiOhJCJ
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2005
    Messages
    206
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2005
    Messages : 206
    Par défaut pow(2, 54) et pow(2, 54) - 1 donnent le même résultat
    Bonjour,

    Voici le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #include <stdio.h> /* for printf */
    #include <math.h> /* for pow */
    #include <errno.h> /* for errno */
    int main()
    {
    	double res = -1;
    	/* first calcul */
    	errno = 0;
    	res = pow(2, 54);
    	printf("errno = %d\n", errno);
    	printf("res = %f\n", res);
    	/* second calcul */
    	errno = 0;
    	res = pow(2, 54) - 1;
    	printf("errno = %d\n", errno);
    	printf("res = %f\n", res);
    	return 0;
    }
    Voici le résultat espéré :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $ ./main.out 
    errno = 0
    res = 18014398509481984.000000
    errno = 0
    res = 18014398509481983.000000
    Voici le résultat obtenu :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $ ./main.out 
    errno = 0
    res = 18014398509481984.000000
    errno = 0
    res = 18014398509481984.000000
    Remarque : en Python ça fonctionne bien
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ python
    Python 2.7.14 (default, Jan 22 2018, 12:57:03) 
    [GCC 7.1.0] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> 2 ** 54
    18014398509481984
    >>> (2 ** 54) - 1
    18014398509481983
    >>> quit()
    Je ne comprends pas pourquoi pow(2, 54) et pow(2, 54) - 1 donnent le même résultat.
    Une explication s'il vous plaît ?

    Merci.
    Cordialement.

  2. #2
    Membre expérimenté
    Homme Profil pro
    Ingénieur R&D
    Inscrit en
    Mai 2016
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ingénieur R&D
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2016
    Messages : 313
    Par défaut
    Erreur d'arrondi.
    Le type 'double' a 16 chiffres significatifs en décimal.

  3. #3
    Membre très actif
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    548
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 548
    Par défaut
    Bonjour,
    Citation Envoyé par wolinn Voir le message
    Erreur d'arrondi.
    Le type 'double' a 16 chiffres significatifs en décimal.
    Ce n’est pas vraiment une question de précision/arrondi, mais plutôt une question d’interprétations des données en clair le résultat de pow(2,54)-1) donne un long double et non un double donc il faut utiliser une autre fonction de puissance qui manipule les long double qui est powl(2,54).
    exemples simples.
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    #include <stdio.h>
    #include <math.h>
     
    int main(int argc, char *argv[]){
     
    		double res = -1;
    		res = pow(2, 54) - 1;
    		printf("res = %f\n", res);
     
    		long double res_a = ((powl(2, 54)) - 1);
    		printf("res = %Lf\n", res_a);
     
     
    		/*	la plus simple et direct	*/
    		printf("res = %Lf\n", (powl(2,54)-1) );
    		return 0;
    }
    à bientôt

  4. #4
    Membre expérimenté
    Homme Profil pro
    Ingénieur R&D
    Inscrit en
    Mai 2016
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ingénieur R&D
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2016
    Messages : 313
    Par défaut
    Citation Envoyé par sambia39 Voir le message
    Bonjour,
    ...donc il faut utiliser une autre fonction de puissance qui manipule les long double qui est powl(2,54).
    Donc c'est un bien un problème de précision/arrondi, qui se résout ici en utilisant le type 'long double', qui a quelques chiffres significatifs en plus.

  5. #5
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Sur une architecture x86_64, les long double sont en général des format réels étendus : 80 bits utilisés pour 63 bits de mantisse. Ce qui fait qu'ils sont capables de représenter les entiers 64bit exactement. Mis bon si tu travailles sur les entiers autant prendre un int64_t …
    Sinon il y a les bibliothèques pour travailler en précision arbitraire comme GMP mais ça a un coût mémoire et temps.

  6. #6
    Membre très actif
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    548
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 548
    Par défaut
    Citation Envoyé par wolinn Voir le message
    Donc c'est un bien un problème de précision/arrondi, qui se résout ici en utilisant le type 'long double', qui a quelques chiffres significatifs en plus.
    Non ce n'est pas dû au nombre significatif, précision ou arrondi, mais à la taille mémoire nécessaire au stockage du résultat de pow(2,54); . Je m’explique. En langage de programmation C, toute variable est typée explicitement et le fait qu’une variable soit typée permet à votre ordinateur de connaître la taille mémoire nécessaire au stockage de l’information, mais aussi comment il faut interpréter la suite des bits qui composent cette information. La mémoire d’un ordinateur étant une mémoire finit, les types que l’on utilise dépendants donc de l’architecture machine et du compilateur que l’on utilise.
    Plus en détail et de façon simple. Un double est un float plus longs et un long double est un double plus longs ont a donc ici deux tailles mémoire qui ne sont pas équivalents . Le fait d'utiliser long double a l’avantage de stockers beaucoups plus d'informations, car il manipule 10 bytes ce qui permet d’avoir une précision de 19 contrairement à double qui en manipule que 8 bytes avec une précision de 15.

    à bientôt.

  7. #7
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 815
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 815
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par sambia39 Voir le message
    Non ce n'est pas dû au nombre significatif, précision ou arrondi, mais à la taille mémoire nécessaire au stockage du résultat de pow(2,54);.
    Ben oui mais c'est la taille mémoire qui influe sur l'imprécision de la partie décimale d'un nombre...
    Exemple: prenons pi= 3,1415 9265 3589 793. Sur un float, on aura 3.1416. Sur un double on aura 3.1415 9265 et sur un long double on aura 3.1415 9265 3590 (ces précisions à 4, 8 et 12 décimales sont inventées pour illustrer l'exemple et ne correspondent pas forcément à la réalité). Donc c'est bien le type utilisé qui amène alors à plus ou moins de précision non ?
    Surtout que le calcul des puissances passe probablement par une méthode à base de logarithmes qui est alors plus rapide mais qui amène à des calculs en flottant (même pour calculer 3²)...

    Citation Envoyé par YuGiOhJCJ Voir le message
    Remarque : en Python ça fonctionne bien
    Oui, parce que Python possède un type spécial nommé "long" qui n'existe pas en C (et qui ne correspond donc pas au long du C) et qui adapte automatiquement sa taille à l'espace nécessaire pour le nombre à manipuler. Les calculs sont plus longs avec un long (promis après j'arrête ce genre de jeu de mots débiles) mais il n'y a aucune perte d'information ni arrondi.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  8. #8
    Membre très actif
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    548
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 548
    Par défaut
    La taille de stockage et l’interprétation du nombre rentrent en comptes aussi mais tout dépendent fortement de l’architecture et du compilateur que vous utilisez. Les compilateurs doivent respecter les standards for Binary Floating-Point Arithmetic IEEE 754-2008 (la révivions de la IEEE 754 -1985) / Binary floating-point arithmetic for microprocessor system IEC 60559:1989, mais aussi l’ISO/IEC/IEEE 60559:2011 pour Information technology -- Microprocessor Systems -- Floating-Point arithmetic.
    Ainsi donc, la précision détermine, le nombre de bits nécessaire a utilisé pour la mantisse(donc espace de stockage suffisant). Dans l'exemple précédent, un double n'a pas le même nombre de mantisses qu'un long double. (double = 52bits contre 64 pour un long double) Désolé pour l'exemple ci-dessous qui n'est pas corrects, mais bon, je prends le risque que cela pique les yeux et vous faire brutaliser vos claviers.
    à bientôt.
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
     
    int main(int argc, char *argv[]){
     
    	float a = (-1*1.25)*powf(2,1);
    	double b = (-1 * 1.25)*pow(2,1);
    	long double c = (-1 * 1.25)*powl(2,1);
    	(void)fprintf(stderr, 
    		"float = \t%f\ndouble = \t%f\nlong double = \t%Lf\n",
    		a, b, c);
     
    	(void)puts("-----------------------\n");
    	a = (-1*1.25)*powf(2,200);
    	b = (-1 * 1.25)*pow(2,200);
    	c = (-1 * 1.25)*powl(2,200);
    	(void)fprintf(stderr, 
    		"float = \t%f\ndouble = \t%f\nlong double = \t%Lf\n",
    		a, b, c);
     
    	(void)puts("-----------------------\n");		
    	a = (-1*1.25)*powf(2,1024);		
    	b = (-1 * 1.25)*pow(2,1024);
    	c = (-1 * 1.25)*powl(2,1024);
    	(void)fprintf(stderr, 
    		"float = \t%f\ndouble = \t%f\nlong double = \t%Lf\n",
    		a, b, c);
     
    	(void)puts("-----------------------\n");		
    	a = (-1*1.25)*powf(2,(10*BUFSIZ));		
    	b = (-1 * 1.25)*pow(2,(10*BUFSIZ));
    	c = (-1 * 1.25)*powl(2,(10*BUFSIZ));
    	(void)fprintf(stderr, 
    		"float = \t%f\ndouble = \t%f\nlong double = \t%Lf\n",
    		a, b, c);
     
    	(void)puts("-----------------------\n");		
    	a = (-1*1.25)*powf(2,(BUFSIZ*BUFSIZ));		
    	b = (-1 * 1.25)*pow(2,(BUFSIZ*BUFSIZ));
    	c = (-1 * 1.25)*powl(2,(BUFSIZ*BUFSIZ));
    	(void)fprintf(stderr, 
    		"float = \t%f\ndouble = \t%f\nlong double = \t%Lf\n",
    		a, b, c);
     
     
    	return EXIT_SUCCESS;		
    }

    Code SORTIE : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    float = 	-2.500000
    double = 	-2.500000
    long double = 	-2.500000
    -----------------------
     
    float = 	-inf
    double = 	-2008672555323737844427452615426453253152753742228491044126720.000000
    long double = 	-2008672555323737844427452615426453253152753742228491044126720.000000
    -----------------------
     
    float = 	-inf
    double = 	-inf
    long double = 	-224711641857789488466163148848628091702247122367788321591787601447165844756876203915885596653009420026400142349839241697073487211018020778116059288299342655472209866781081856595377774501557617649316353690106257211047688352928078601842391388176034046454188138355732872799934057423099645381044195412030280171520.000000
    -----------------------
     
    float = 	-inf
    double = 	-inf
    long double = 	-44062142651354783214185185497503519330489276679958088825489228257163837846068436706310412870592079828071210194244122967466573811844928892024860423341395167083518383588456589884570257057523260462481948401584587902173789923292291602361490775198033164758653930299087158595499939951489975435029114629340382204728012993237198668232038888847650544128790861023439308044114214196464694540969203665868493845391795859337047505409611737808419152319788263571082406142201033454720004082314645696667763302846679344697249725623776949778015542843858855396616818911963008384487502589630841419409416929021694984460134621972433482245515570060450091207021088781082805812601323835228797668148142778733983546743247524824391242000474045237746971048631350916699986368358761249270309652525077490699914252340446724635610731254583707413262163038467634259367522581707306346367900668375865443000212280164472986442071145943352815531953428618783527607640295232211164925541655098365483079552972536614477980688630015355331596405834316021232074171871976239490637751849708126096784793208273945392985134482179432861334438815542594597744181716704899464154012642028269389706417912034009944742006721116094922947091088601632099131901616699969284752402496918614342613585141834197230449729228863857146376009035531289033471231496705449255853801883267429558332749318624204607252310970912107297254035270142292318428054261526850562790703913022137031650993714590922171732479969400059674972706406133646072414951128009247301920822062973447515511446507424391356655353049112636136336295644288362949953941233234687413146100837907681296234508816202120976945523188707752278527322472525078171030019622026196528422581923540233871762324378336495736282451499310948746717241216489654169437215493598592563568165982403094778545504742483278991467526164290476773046278450515852845478736693549531816551612258885326131417793348913693584463059193187200218363758848160565931284993679816536850680640461039223451399602020899159546635177893881400660880854393977547900281348331642389664686705319526605542881181796518261757510800651215036887444294460118611019626838024263611445654963977716018029092676194285088242910477083810358464966072129294407254430884793209717534008267679274978012636577413372888763572343583550929814341072056663661461935504688855618407367161694313092213824983501322927527378419209534876218590460172298745496724872701818532463638416072753476603717422053559966727298341225866748799286678266251993936210102512520076277895303552959590926581756793191384120779449505516657940175662022713969313322355318874168273403414622400231978046477989247091626460200853145799018383208726832452164218511186414677955941241347907959642646251755263662814422665552774168840840121081480864128783946203049721317134108229937205068939114770503183078065898918496473874012791971995347407057539780215343592605702641800054246743988831842025896380313357551120726160876053242398966604805664338690257001093102878110654833843166134726581238581689805856008765260048885359455668568125607989423595079514345832025287868514335439794217590075662769884886639102270164927774720.000000
    -----------------------
     
    float = 	-inf
    double = 	-inf
    long double = 	-inf

Discussions similaires

  1. [visual 2005] erreur à la compilation: pow
    Par r0d dans le forum Visual C++
    Réponses: 9
    Dernier message: 28/11/2006, 16h56
  2. Problème avec la fonction pow(les puissance)
    Par Clément76 dans le forum C
    Réponses: 10
    Dernier message: 04/10/2006, 12h44
  3. Probleme avec pow(x,y)
    Par Yruama dans le forum C
    Réponses: 4
    Dernier message: 01/09/2006, 11h54
  4. erreur avec pow et sqrt
    Par salseropom dans le forum C
    Réponses: 3
    Dernier message: 12/12/2005, 19h24
  5. Résultat incohérent de pow, sqrt
    Par PierrotY dans le forum C++
    Réponses: 15
    Dernier message: 16/03/2005, 12h07

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo