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 :

Max d'un 'double' atteint prématurement?


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre habitué
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2003
    Messages
    9
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2003
    Messages : 9
    Par défaut Max d'un 'double' atteint prématurement?
    Bonjour, voici mon problème:
    Je stocke des millisecondes dans une variable 'double'. Je les affiche dans un printf avec %lf.
    Jusqu'à 2 millions de ms, sa marche. Mais quand il est censé m'afficher une valeur au alentour d'une heure (3,6 millions de ms) sa passe dans les négatifs, comme s'il avait atteint le maximum stockable dans ce type de donnée(double). Je dis sa car il se passe au près pareil quand on dépasse 32000 et quelque, avec un int.

    Je vous donne un bout de code pour mieux visualiser la chose. Je calcul le temps moyen sur 20 essais que met une fonction de Tri a trier un tableau. (20 essais car on réaffecte aleatoirement tout le tableau à chaque fois, pour plus d'objectivité)
    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
    int i;
    clock_t debut, fin;
    double tps = 0;
    
    for(i=0; i<20; i++)
    {
      debut = clock();
      MaFct();
      fin = clock();
    
      tps += (((double)(fin - debut))/CLOCKS_PER_SEC) *1000.0;  //en ms
    }
    //Affichage du temps moyen
    printf("%lf", tps/i);
    (C'est simplifié, je peux donner le code réel en cas)
    Donc en fct de la taille du tableau (100 à 700000 éléments) que la fonction trie, sa va de 0 à 2 millions de ms. Mais pour la taille au dessus (800 000), le temps n'atteignant pas des milliers de millards de milliseconde, sa devrait rentrer sans problème dans un double non?
    Merci d'avance

  2. #2
    Expert confirmé
    Avatar de Skyounet
    Homme Profil pro
    Software Engineer
    Inscrit en
    Mars 2005
    Messages
    6 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Software Engineer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 6 380
    Par défaut
    Tu peux utiliser un unsigned int, tu doublera de capacité

  3. #3
    Membre habitué
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2003
    Messages
    9
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2003
    Messages : 9
    Par défaut
    Ok je vais (mais c'est long )
    Ceci dit je crois que sa va jusqu'à 3.4 x 10^300 quelque chose comme sa un double non?

    edit: unsigned double sa existe pas? Parce que gcc me met: "Error: Both "unsigned" and "double" in declaration specifiers"

  4. #4
    Expert confirmé
    Avatar de Skyounet
    Homme Profil pro
    Software Engineer
    Inscrit en
    Mars 2005
    Messages
    6 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Software Engineer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 6 380

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 480
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 480
    Par défaut
    Citation Envoyé par clood200 Voir le message
    edit: unsigned double sa existe pas? Parce que gcc me met: "Error: Both "unsigned" and "double" in declaration specifiers"
    Non.

    Ok je vais (mais c'est long )
    Ceci dit je crois que sa va jusqu'à 3.4 x 10^300 quelque chose comme sa un double non?
    Si, mais pas sans contrainte :

    http://www.developpez.net/forums/d64...apres-virgule/
    http://www.developpez.net/forums/d64...s/#post3783703
    http://www.developpez.net/forums/d63...imal-printf-f/

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 480
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 480
    Par défaut
    Citation Envoyé par clood200 Voir le message
    Mais pour la taille au dessus (800 000), le temps n'atteignant pas des milliers de millards de milliseconde, sa devrait rentrer sans problème dans un double non?
    Déjà, tu fais ta conversion en double avant de faire ta division, et par conséquent tu ne prends pas en considération la valeur de CLOCKS_PER_SEC. Sur mon Linux, ça donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    /usr/include/bits/time.h:#  define CLOCKS_PER_SEC  1000000l
    Soit 3,6 milliards de clocks par heure. Toutefois, la mantisse d'un double tenant sur 53 bits, on est encore loin de la perte de précision, et très loin du débordement. Ce qui n'est pas une raison pour utiliser un flottant sur 64 bits là ou un entier non signé aurait parfaitement fait l'affaire.

    Néanmoins, debut et fin restent des clock_t jusqu'à la fin de la soustraction. En cherchant un peu :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    /usr/include/bits/types.h:__STD_TYPE __CLOCK_T_TYPE __clock_t;  /* Type of CPU usage counts.  */
    /usr/include/bits/typesizes.h:#define __CLOCK_T_TYPE __SLONGWORD_TYPE
    /usr/include/bits/types.h:#define __SLONGWORD_TYPE      long int
    Les clock_t sont donc - dans cette implémentation - des long int, soit généralement 32 bits, sur une architecture du même format, et ils ne peuvent par conséquent coder une valeur aussi grande que 3,6 milliards. Donc, à ce stade, tu as atteint le débordement à coup sûr.

    En outre, nous n'avons aucune idée du temps déjà écoulé lorsque ton programme fait son premier appel à clock(), qui agira d'autant sur le laps de temps maximum que tu veux mesurer, et pour finir :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $ man clock
    
    RETURN VALUE
           The value returned is the CPU time used so far as a clock_t; to get the number of seconds used, divide by CLOCKS_PER_SEC.
           If the processor time used is not available or its value cannot be represented, the function returns the value (clock_t) -1.
    Et ton code ne tient absolument pas compte de cette éventualité.

    UPDATE : Tiens, puis je m'aperçois que c'est écrit blanc sur noir :-) dans la même man page :

    Note that the time can wrap around. On a 32-bit system where CLOCKS_PER_SEC equals 1000000 this function will return the same value approximately every 72 minutes.

    On several other implementations, the value returned by clock() also includes the times of any children whose status has been collected via wait(2) (or another wait-type call). Linux does not include the times of waited-for children in the value returned by clock(). The times(2) function, which explicitly returns (separate) information about the caller and its children, may be preferable.

  7. #7
    Membre habitué
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2003
    Messages
    9
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2003
    Messages : 9
    Par défaut
    Merci pour ta réponse.
    J'ai essayer des modifications suite à ce que tu m'as dit:
    .J'ai pris le CLOCKS_PER_SEC en compte avant le transtypage
    .Pour ne pas être limiter par clock_t, j'ai mis les variables 'debut' et 'fin' en double
    Sa donne ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    double debut, fin;
    double tps = 0;
    
    for(i=0; i<20; i++)
    {
      debut = clock() * 1.0/CLOCKS_PER_SEC;
      MaFct();
      fin = clock() * 1.0/CLOCKS_PER_SEC;
    
      tps += (fin - debut) *1000.0;  //une difference de seconde convertie en ms
    }
    Sa ne marche toujours pas (pour des temps depassant 2500-3000 seconde), malgès differentes petites variantes du code.
    Je n'ai par contre pas pris en compte le -1 eventuel en retour de clock(). Ce qui est étrange c'est que c'est un projet dans le cadre d'un TP, avec donc des instructions sur papier, où il n'y a pas mention de cette possibilité (-1) , ainsi que d'un eventuel debordement. De plus mes collègues n'ont pas eu ce problème apparement, et il ne sont pas aller chercher plus loin que ce qui était demander. Je vais demander à mon chargé de TP, mais c'est vendredi, et je doute qu'il ai une réponse; c'est pourquoi je suis ici
    Je suis sous linux, mais en cours on y est aussi, sa ne doit pas venir de là. Cela m'intrigue. Si quelqu'un a une idée

  8. #8
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par clood200 Voir le message
    Merci pour ta réponse.
    J'ai essayer des modifications suite à ce que tu m'as dit:
    .J'ai pris le CLOCKS_PER_SEC en compte avant le transtypage
    .Pour ne pas être limiter par clock_t, j'ai mis les variables 'debut' et 'fin' en double
    Sa donne ceci:
    Je conseille de limiter les conversions au strict nécessaire :
    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
    19
    20
    21
    22
    23
    24
    25
    26
     
    #include <time.h>
     
    void MaFct (void)
    {
       int volatile i;
       for (i = 0; i < 10000000; i++)
       {
       }
    }
     
    int main (void)
    {
       clock_t debut;
       clock_t tps = 0;
       int i;
     
       for (i = 0; i < 20; i++)
       {
          debut = clock ();
          MaFct ();
          tps += (clock () - debut);
       }
       printf ("tps = %.2f ms\n", tps * 1000.0 / CLOCKS_PER_SEC);
       return 0;
    }
    Windows :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    tps = 895.00 ms
     
    Process returned 0 (0x0)   execution time : 0.931 s
    Press any key to continue.

  9. #9
    Membre habitué
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2003
    Messages
    9
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2003
    Messages : 9
    Par défaut
    Merci du conseil. Je fais un bilan:
    Pour un temps d'éxécution inferieur a 45min - 1h, mon code marche, j'ai un resultat en ms (ou seconde a ma guise).
    Pour un temps superieur (tri lent d'un tableau a 800 000 éléments dans mon exemple, mais un tri plus lent ferai pareil pour un tableau de 400 000 éléments), on me renvoie un temps négatif, et complètement faussé.
    Tout cela est pareil que ce soit avec mon code de base, ou un code optimisé au maximum.
    Il y a donc un problème de débordement ou un truc similaire, que je ne comprend pas puisque avec des modifications, comme utilisé un double au lieu de clock_t, sa change rien. Cela est d'autant plus étrange que ça n'arrive qu'à moi apparement, pas à mes camarades, donc sa ne devrait pas venir du fonctionnement interne de clock().
    Je cherche toujours de l'aide, peut-être plus explicite si la réponse m'a en faite déjà été donné, puisque je ne la vois pas.
    Peut-être ceci que je ne comprend pas:
    On several other implementations, the value returned by clock() also includes the times of any children whose status has been collected via wait(2) (or another wait-type call). Linux does not include the times of waited-for children in the value returned by clock(). The times(2) function, which explicitly returns (separate) information about the caller and its children, may be preferable.
    Merci d'avance

  10. #10
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 480
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 480
    Par défaut
    Citation Envoyé par clood200 Voir le message
    .Pour ne pas être limiter par clock_t, j'ai mis les variables 'debut' et 'fin' en double
    Mauvaise approche. Tu ne peux pas changer le type des données à volonté, comme çà, sans y jeter un oeil. Ici, ça marche parce qu'on sait que clock_t est en fait un long int, mais ce n'est pas garanti sur toutes les plateformes. D'ailleurs, on pourrait très bien imaginer un long long par défaut sur des archis 64 bits par exemple, ce qui suffirait à court-circuiter ton double.

    Sa donne ceci:
    Le « ç » se trouve sur la touche « 9 » ! :-)

    Sa ne marche toujours pas (pour des temps depassant 2500-3000 seconde), malgès differentes petites variantes du code.
    Je n'ai par contre pas pris en compte le -1 eventuel en retour de clock(). Ce qui est étrange c'est que c'est un projet dans le cadre d'un TP, avec donc des instructions sur papier, où il n'y a pas mention de cette possibilité (-1) , ainsi que d'un eventuel debordement.
    C'est pas dur de faire le calcul : la man-page affirme que clock() renvoie la même valeur toutes les 72 minutes environ. Le fait que le résultat de clock() en lui-même soit positif ou négatif importe peu, mais à l'issue de ta soustraction, une valeur qui représente une durée supérieure à 36 minutes ne pourra être représentée positivement dans un long int signé de 32 bits.

    De plus mes collègues n'ont pas eu ce problème apparement, et il ne sont pas aller chercher plus loin que ce qui était demander. Je vais demander à mon chargé de TP, mais c'est vendredi, et je doute qu'il ai une réponse; c'est pourquoi je suis ici
    Ça dépend beaucoup de ce que tu mesures : clock() sert à calculer le temps processeur consommé par le processus. Si tu mets un gros sleep(1000) dans ta fonction, ça ne fera pas avancer le compteur.

    Je suis sous linux, mais en cours on y est aussi, sa ne doit pas venir de là. Cela m'intrigue. Si quelqu'un a une idée
    clock() n'est visiblement pas faite pour mesurer des intervalles de temps si larges. Si tu as réellement l'intention de mesurer le temps CPU consommé, il vaut mieux que tu fasses des mesures à intervalles réguliers et que tu fasses toi-même le cumul.

    Autrement, si ce qui t'intéresse est le temps passé entre le moment où l'on est entrée et celui où on est ressorti (que ce soit en consommant du temps ou en attendant un retour du système), tu peux utiliser time() et difftime(). La première te donne « l'heure calendaire courante » dans un format non défini par la norme mais qui correspond au nombre de secondes écoulées depuis le 1er janvier 1970 sous Unix. La seconde sert à comparer deux dates et à te renvoyer la différences en secondes dans un double. Elles font toutes les deux parties de la norme.

  11. #11
    Membre habitué
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2003
    Messages
    9
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2003
    Messages : 9
    Par défaut
    Mauvaise approche. Tu ne peux pas changer le type des données à volonté, comme çà, sans y jeter un oeil
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    debut = (double)(clock()*1.0/CLOCKS_PER_SEC);
    fct();
    fin= (double)(clock()*1.0/CLOCKS_PER_SEC);
    //tps += (fin-debut)*1000.0;
    Je ne comprend pas pourquoi "long int" ou "long long" (du clock_t) change quelque chose au resultat converti en double.

    Sinon le but de ce projet était de mesurer le temps mis pour un tri (choisit via un menu) pour trier un tableau (allant de 100 à 1 000 000 d'éléments), puis d'en faire des courbes et autres joyeustés. Il était donc inévitable de passer par des temps conséquents pour les tris dit lents ("Insertion sequentielle" ou encore pire "Tri à bulles"). N'ayant aucune mention quant à une solution alternative (telle time()), j'en conclut que ce sujet n'était pas totalement résolvable (hormis pour mes collègues qui ont utilisé grossomodo la mm méthode) à cause des limitations de clock() ou clock_t.
    Merci pour les recherches et l'aide en tout cas

  12. #12
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 480
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 480
    Par défaut
    Citation Envoyé par clood200 Voir le message
    Je ne comprend pas pourquoi "long int" ou "long long" (du clock_t) change quelque chose au resultat converti en double.
    Parce que ces formats ne sont pas magiques et qu'ils ont leur limitations, qu'il faut connaître. En l'occurence, sur ta machine, un long long sera codé sur 64 bits, soit autant qu'un double. Comme la mantisse d'un double tient sur 53 bits, tu ne pourrais pas coder à l'unité près les grandes valeurs que tu stockerais dans ton long long, ce qui, en plus, ne servirait à rien.

    N'ayant aucune mention quant à une solution alternative (telle time()), j'en conclut que ce sujet n'était pas totalement résolvable (hormis pour mes collègues qui ont utilisé grossomodo la mm méthode) à cause des limitations de clock() ou clock_t.
    Bien sûr que si ! c'est dans le dernier paragraphe de mon précédent commentaire. Si tu ne peux pas tout mesurer en une fois, tu le fais en plusieurs, et tu fais le cumul dans un long long ! Tu peux par exemple décider de faire un relevé tous les 1000 ou 10.000 éléments traités. Ou alors, sachant que tu as 30 bonnes minutes garanties valides si jamais le programme tournait à 100%, tu colles un timer qui fera le relevé automatiquement (et tu n'oublies pas non plus de le faire à la fin).

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. le max de connections jamais atteint
    Par Oratorio dans le forum MS SQL Server
    Réponses: 4
    Dernier message: 20/11/2010, 12h29
  2. le max de connections jamais atteint
    Par Oratorio dans le forum Sybase
    Réponses: 3
    Dernier message: 08/11/2010, 14h03
  3. tmpfile() nombre de fichiers max atteint!
    Par Rodinia dans le forum Bibliothèque standard
    Réponses: 12
    Dernier message: 22/07/2009, 00h12
  4. Réponses: 2
    Dernier message: 27/08/2005, 16h12
  5. Réponses: 1
    Dernier message: 04/04/2005, 11h19

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