Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Défis]#11 : zPrintf

    15 mai 2012 à 21:02:21

    Bonjour à tous,

    Cette semaine, le but de ce défi est de recoder la célèbre fonction printf. Bien entendu, nous n'allons pas faire une fonction aussi complexe et complète que l'originale, mais néanmoins notre version reprendra les bases de printf.

    Si vous souhaitez plus de renseignements sur les défis, rendez vous sur le topic de recensement des défis, vous y trouverez également les règles principales.

    zPrintf



    Retour sur la fonction originale



    La fonction printf sert à produire des sorties sur le flux standard stdout. Elle permet ainsi non seulement d'afficher une chaîne de caractères, mais permet aussi de prendre et d'afficher autant d'arguments que l'on veut :

    printf("Salut %s, %d, %c", "zero", 42, 'z');
    


    Et ces arguments peuvent recevoir des attributs, comme n'afficher que 2 chiffres après la virgule, ou bien écrire en écriture scientifique. Ces arguments sont très nombreux, et pour les découvrir je vous renvoie à la page de man de printf.

    Pistes



    Notre but est de faire un mini-version de printf. Or on sait que cette fonction peut prendre autant de paramètre que l'on veut. Il faut donc penser à la gestion des paramètres. Il faut aussi gérer les différents attributs, ainsi que trouver comment afficher le résultat. Dernier point : il ne faut pas oublier que les nombres doivent être convertis en chaînes de caractères. ;)

    Consignes



    Le but n'est pas de recopier entièrement la fonction printf, ce qui est compliqué et assez long, mais de faire une version simplifiée. On doit néanmoins pouvoir utiliser les principaux indicateurs de conversion :

    zPrintf("Salut %d %i %c %.3f\n %s", 42, -24, 'a', 2.718281828, "zPrintf");
    


    Salut 42 -24 a 2.718
    zPrintf


    Pour rendre l'exercice plus amusant, les seuls éléments de la bibliothèque standard autorisés sont la fonction fwrite et les macros va_start, va_arg et va_end. Toutes les autres fonctions utilisées doivent être recodées.

    Objectifs



    • Manipuler les fonctions à nombre variable d'arguments.
    • Apprendre à réfléchir aux fonctions utilisées.
    • Découvrir de manière approfondie la bibliothèque standard.


    Énoncé



    Niveau 1

    Dans un premier temps, il ne faudra gérer que %c, %d, %i et %s, ainsi que %%.

    zPrintf("%d %s", 4882, "SdZ");
    


    doit afficher :

    4882 SdZ


    Pensez à une fonction pour convertir les nombres en chaîne de caractères.

    Niveau 2

    Cette fois, le programme doit gérer %o, %u, %x et %X.

    zPrintf("%d %o %X", 47, 47, 47);
    


    doit afficher :

    47 57 2F


    Essayez de reprendre votre fonction de conversion et de l'adapter pour la rendre générique pour n'importe quelle base. ;)

    Niveau 3

    La prochaine étape prend en charge les flottants et l'écriture scientifique avec %f, %F %e, %E, %g, %G, %a et %A.

    zPrintf("%f %e %G", 3.1415, 3.1415, 3.1415);
    


    doit afficher :

    3.141500 3.141500e+000 3.1415


    Niveaux supplémentaires

    La page de man ! Essayez d'implémenter le plus de choses possibles, comme les caractères d'attribut, les modificateur de longueur, les largeurs de champ, la précision, etc. Si vous le souhaitez, vous pouvez créer vos propres indicateurs de fonctions ou vos propres modificateurs. Vous pouvez également tenter de réécrire d'autres fonctions de la famille de printf. Votre imagination est votre seule limite !

    Bon courage à tous et amusez-vous bien. ;)

    PS : si vous n'avez pas compris quelque chose, n'hésitez pas à poser votre question.


    Participants



    Participants Code
    informaticienzero Niveau 2
    Lucas-84 Niveau 1
    Niveau 2
    Taurre Niveau 3
    sasuke78200 Niveau 2
    Maëlan Niveau 2
    • Partager sur Facebook
    • Partager sur Twitter
    Anonyme
      15 mai 2012 à 22:49:33

      Voilà ma participation pour le niveau 2 :

      #include <stdarg.h>
      #include <stdio.h>
      
      #define BUFF_SIZE   256
      
      void my_putchar(char c)
      {
          fwrite(&c, sizeof(char), 1, stdout);
      }
      
      int itos(int nombre, int base)
      {
          char buff[BUFF_SIZE];
          char lettre[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
          int cmp, temp, res;
      
          cmp = temp = res = 0;
      
          if (nombre < 0)
              res++, putchar('-');
      
          do
          {
              temp = nombre % base;
              temp = (temp < 0) ? -temp : temp;
              buff[cmp] = lettre[temp];
              cmp++;
              nombre /= base;
      
          } while (nombre != 0);
      
          for (cmp = cmp - 1; cmp >= 0; cmp--)
          {
              putchar(buff[cmp]);
              res++;
          }
      
      
          return res;
      }
      
      int my_vprintf(const char * str, va_list args)
      {
          int i, res;
      
          i = res = 0;
      
          for (i = 0; str[i] != '\0';i++)
          {
              switch(str[i])
              {
                  case '%':
                      i++;
                      switch(str[i])
                      {
      
                          case 'b':
                          {
                              int entier = va_arg(args, int);
                              res += itos(entier, 2);
                              i++;
                          }
                          break;
      
                          case 'o':
                          {
                              int entier = va_arg(args, int);
                              my_putchar('0');
                              res += itos(entier, 8) + 1;
                              i++;
                          }
                          break;
      
                          case 'i':
                          case 'd':
                          {
                              int entier = va_arg(args, int);
                              res += itos(entier, 10);
                              i++;
                          }
                          break;
      
                          case 'u':
                          {
                              unsigned int entier = va_arg(args, unsigned int);
                              res += itos(entier, 10);
                              i++;
                          }
                          break;
      
                          case 'X':
                          {
                              int entier = va_arg(args, int);
                              my_putchar('0');
                              my_putchar('x');
                              res += itos(entier, 16) + 2;
                              i++;
                          }
                          break;
      
                          case 'c':
                          {
                              char c = (unsigned char)va_arg(args, int);
                              my_putchar(c);
                              i++, res++;
                          }
                          break;
      
                          case 's':
                          {
                              char * s = va_arg(args, char *);
                              for (; *s != '\0'; s++)
                              {
                                  my_putchar(*s);
                                  res++;
                              }
      
                              i++;
                          }
                          break;
      
                          case '%':
                              my_putchar('%');
                              res++;
                          break;
      
                          default:
                              my_putchar('%');
                              res++;
                          break;
                      }
      
                  default:
                      my_putchar(str[i]);
                      res++;
                  break;
              }
          }
      
          return res;
      }
      
      int my_printf(const char * str, ...)
      {
          int res;
          va_list ap;
      
          va_start(ap, str);
      
          res = my_vprintf(str, ap);
      
          va_end(ap);
      
          return res;
      }
      
      int main(void)
      {
          int a, b;
      
          a = my_printf("%d %i %c %s\n", 24577, -21, 'a', "Sa");
          b = printf("%d %i %c %s\n", 24577, -21, 'a', "Sa");
      
          printf("%d %d \n", a, b);
      
          a = my_printf("Salut\n");
          b = printf("Salut\n");
      
          printf("%d %d \n", a, b);
      
          printf("%d %u\n", -42 , -42);
          my_printf("%d %u\n", -42 , -42);
      
          my_printf("%d %X %o\n", 47, 47, 47);
          my_printf("%d %X %b\n", 0xAA55, 0xAA55, 0xAA55);
          my_printf("%d %X %o %b\n", 11, 11, 11, 11);
      
          return 0;
      }
      


      24577 -21 a Sa
      24577 -21 a Sa
      15 15
      Salut
      Salut
      6 6
      -42 4294967254
      -42 -42
      47 0x2F 057
      43605 0xAA55 1010101001010101
      11 0xB 013 1011



      Le code n'est pas du tout optimisé, je ne gère pas %x à cause d'une mauvaise conception, tout comme %u. De plus, le switch devenant de plus en plus imbuvable, je compte le remplacer par un tableau de pointeurs sur fonctions pour rendre ça plus propre. Je suis donc ouvert à toutes remarques pouvant m'aider à améliorer mon code.
      • Partager sur Facebook
      • Partager sur Twitter
        16 mai 2012 à 17:11:18

        Salut,

        L'exercice est intéressant, cependant il y a deux petites choses qui retienne mon attention :

        - pourquoi n'utiliser que fwrite et les macros de l'en-tête stdarg.h ?
        - vous avez essayer de convertir un flottant en chaîne de caractère avant de proposer cet exercice pour le niveau 3 ? Si oui, je veux bien votre code :-°

        • Partager sur Facebook
        • Partager sur Twitter
        Anonyme
          16 mai 2012 à 17:17:29

          Citation : Taurre

          Pourquoi n'utiliser que fwrite et les macros de l'en-tête stdarg.h ?



          C'est juste pour forcer à recoder toutes les fonctions utilisées, en se basant sur le minimum. C'est un peu inutile, mais ça fait un bon exercice. Sinon je peux très bien faire un simple :

          int my_printf(const char * str, ...)
          {
              int res;
              va_list ap;
          
              va_start(ap, str);
          
              res = vprintf(str, ap);
          
              va_end(ap);
          
              return res;
          }
          


          et pis voilà, j'ai recodé printf.

          Citation : Taurre

          Vous avez essayer de convertir un flottant en chaîne de caractère avant de proposer cet exercice pour le niveau 3 ? Si oui, je veux bien votre code :-°



          Pour tout t'avouer non, mais si cet exercice est si souvent proposé dans les écoles d'informatique, c'est que ça ne doit pas être impossible à faire. Après une simple conversion basique suffira.
          • Partager sur Facebook
          • Partager sur Twitter
            16 mai 2012 à 17:21:18

            Citation : informaticienzero


            C'est juste pour forcer à recoder toutes les fonctions utilisées, en se basant sur le minimum. C'est un peu inutile, mais ça fait un bon exercice. Sinon je peux très bien faire un simple :



            Ma foi, dans ce cas, il suffit d'interdire les fonctions de la famille printf (ce qui est au final assez logique pour un exercice visant à recoder printf :p ), nul besoin d'interdire les autres ;)

            Citation : informaticienzero


            Pour tout t'avouer non, mais si cet exercice est si souvent proposé dans les écoles d'informatique, c'est que ça ne doit pas être impossible à faire. Après une simple conversion basique suffira.



            Hmm... J'avoue que j'ai bon y réfléchir je ne vois pour l'instant pas comment faire cela. Je serais curieux de savoir comment ils s'en sortent à Epitech par exemple :)
            • Partager sur Facebook
            • Partager sur Twitter
            Anonyme
              16 mai 2012 à 17:29:35

              Citation : Taurre

              Hmm... J'avoue que j'ai bon y réfléchir je ne vois pour l'instant pas comment faire cela. Je serais curieux de savoir comment ils s'en sortent à Epitech par exemple :)



              Tiens j'ai trouvé ça sur le site d'un gars qui a recodé toute la libC. Ce lien mène vers les fonctions de conversions de nombres en chaînes.
              • Partager sur Facebook
              • Partager sur Twitter
                16 mai 2012 à 17:53:35

                Citation : informaticienzero


                Tiens j'ai trouvé ça sur le site d'un gars qui a recodé toute la libC. Ce lien mène vers les fonctions de conversions de nombres en chaînes.



                Le lien est intéressant, mais il donne une implémentation de strtod qui converti une chaîne en double. Le but ici est de faire l'inverse ;)
                • Partager sur Facebook
                • Partager sur Twitter
                Anonyme
                  16 mai 2012 à 18:01:06

                  C'est exact, j'ai fais une confusion. ^^
                  Sinon il me semble que ce lien-là montre bien une conversion de double en chaîne.
                  • Partager sur Facebook
                  • Partager sur Twitter
                    16 mai 2012 à 18:20:18

                    Citation : informaticienzero


                    C'est exact, j'ai fais une confusion. ^^
                    Sinon il me semble que ce lien-là montre bien une conversion de double en chaîne.



                    Aah ! Très intéressante comme implémentation, merci pour le lien :)
                    J'avais regardé du côté du code source de FreeBSD et j'étais tombé sur un truc imbuvable :-°
                    • Partager sur Facebook
                    • Partager sur Twitter
                    Anonyme
                      16 mai 2012 à 18:23:34

                      Il n'y a pas de quoi. :)

                      Personnellement je vais essayer de faire une version minimaliste sans regarder le code. Je vais déjà lire le tutoriel de Maëlan sur le sujet.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        16 mai 2012 à 18:45:53

                        OMG ce topic aura un pic de visite chaque début d’année! :D

                        Bon sinon le conseil de base c'est d'avoir conscience que la lettre ne colle pas forcement le '%'

                        printf("%#.2x %+0*d %% [%-10.3s]\n", 1, 5, 21, "Bonjour");
                        0x01 +0021 % [Bon       ]


                        D'ailleurs je n'avais pas remarque mais gcc donne des warnings pour printf, c'est la seule fonction qui est favoriser comme ça ou pas?
                        • Partager sur Facebook
                        • Partager sur Twitter
                          16 mai 2012 à 19:28:37

                          Un truc vite fait pour le niveau 1, histoire d'avoir une participation de base.

                          #include <stdarg.h>
                          #include <stdio.h>
                          #include "printf.h"
                          
                          #define __decompose(n, d, t) \
                              do { \
                                  (t) = (n) / 10; \
                                  (d) = (n) - 10 * (t); \
                              } while (0) 
                          
                          #define __putn(fp, n) \
                              __putchar(fp, (char)((n) + '0'))
                          
                          static int
                          __write(FILE *fp, void *p, size_t n) {
                              return (int)fwrite(p, n, 1UL, fp);
                          }
                          
                          static int
                          __putchar(FILE *fp, int c) {
                              return __write(fp, &c, sizeof c);
                          }
                          
                          static int
                          __convert(FILE *fp, int b, int n) {
                              const char *alpha = "0123456789ABCDEF";
                              int i, d;
                          
                              d = 1;
                              i = 0;
                          
                              while (d <= n)
                                  d *= b;
                          
                              while ((d /= b) >= 1) {
                                  i += __putchar(fp, alpha[n / d]);
                                  n %= d;
                              }
                          
                              return i;
                          }
                          
                          static int 
                          __putuint(FILE *fp, unsigned long long n) {
                              int i;
                              unsigned long long divide, digit;
                          
                              i = 0;
                              __decompose(n, digit, divide);
                          
                              if (divide != 0U)
                                  i = __putuint(fp, divide);
                          
                              return i + __putn(fp, digit);
                          }
                          
                          static int 
                          __putd(FILE *fp, unsigned long long n) {
                              int i;
                              unsigned long long divide, digit;
                          
                              i = 0;
                              __decompose(n, digit, divide);
                          
                              if (digit == 9U) {
                                  if (divide != 0U)
                                      i = __putd(fp, divide);
                                  else
                                      i = __putn(fp, 1);
                          
                                  digit = 0;
                              }
                              else {
                                  if (divide != 0U)
                                      i = __putuint(fp, divide);
                          
                                  ++digit;
                              }
                          
                              return i + __putn(fp, digit);
                          }
                          
                          static int
                          __putint(FILE *fp, long long int n) {
                              int i;
                          
                              if (n < 0) {
                                  __putchar(fp, '-');
                                  i = __putd(fp, (unsigned long long)-(n + 1)) + 1;
                              }
                              else
                                  i = __putuint(fp, (unsigned long long)n);
                          
                              return i;
                          }
                          
                          static int
                          __putstring(FILE *fp, const char *s) {
                              int i;
                          
                              for (i = 0; s[i] != '\0'; ++i)
                                  __putchar(fp, s[i]);
                          
                              return i;
                          }
                          
                          int
                          zVfprintf(FILE *fp, const char *fmt, va_list ap) {
                              int read;
                             
                              read = 0;
                          
                              for (; *fmt != '\0'; ++fmt) {
                                  if (*fmt == '%') {
                                      switch (*++fmt) {
                                      case 'c':
                                          read += __putchar(fp, va_arg(ap, int));
                                          break;
                                      case 'i': case 'd':
                                          read += __putint(fp, va_arg(ap, int));
                                          break;
                                      case 's':
                                          read += __putstring(fp, va_arg(ap, char *));
                                          break;
                                      case 'u':
                                          read += __putuint(fp, va_arg(ap, unsigned));
                                          break;
                                      case 'o':
                                          read += __convert(fp, 8, va_arg(ap, int));
                                          break;
                                      case 'x' : case 'X':
                                          read += __convert(fp, 16, va_arg(ap, int));
                                          break;
                                      default:
                                          read += __putchar(fp, *fmt);
                                      }
                                  }
                                  else
                                      read += __putchar(fp, *fmt);
                              }
                          
                              return read;
                          }
                          
                          int
                          zFprintf(FILE *fp, const char *fmt, ...) {
                              int i;
                              va_list ap;
                          
                              va_start(ap, fmt);
                              i = zVfprintf(fp, fmt, ap);
                              va_end(ap);
                          
                              return i;
                          }
                          
                          int
                          zPrintf(const char *fmt, ...) {
                              int i;
                              va_list ap;
                          
                              va_start(ap, fmt);
                              i = zVfprintf(stdout, fmt, ap);
                              va_end(ap);
                          
                              return i;
                          }
                          


                          Le seul truc qui peut à la rigueur poser problème à la relecture c'est le récursif de l'affichage du nombre. On fait ça chiffre par chiffre.
                          • Partager sur Facebook
                          • Partager sur Twitter
                          Staff désormais retraité.
                            16 mai 2012 à 21:47:27

                            line 47: The left operand of '+' is a garbage value

                            J'ai plein de ça aussi :

                            Implicit conversion loses integer precision: 'size_t' (aka 'unsigned long') to 'int'
                            • Partager sur Facebook
                            • Partager sur Twitter
                              18 mai 2012 à 15:17:13

                              Yop,

                              static inline size_t
                              __putchar(int c) {
                                  return fwrite(&c, 1, 1, stdout);
                              }
                              


                              Attention qu'avec cette fonction tu écris le byte de poids faible de la variable c, tu écriras donc probablement 0 sur une machine big endian. De plus, le retour de putchar doit être de type int (retourne EOF en cas d'erreur) et non size_t.

                              EDIT : Aussi, les noms d'identificateurs commençant par deux underscores sont réservés et ne doivent par conséquent pas être utilisés ;)

                              @informaticienzero: j'ai fait quelque test sur le principe de la fonction que tu m'as passée en lien et malheureusement cela ne fonctionne plus lorsque l'on dépasse des nombres d'une certaine taille. Par exemple, le code suivant :


                              #include <float.h>
                              #include <math.h>
                              #include <stdio.h>
                              
                              
                              int
                              main(void)
                              {
                              	double n = FLT_MAX;
                              	double i, f;
                              
                              	f = modf(n, &i);
                              	printf("%f, %f\n", i, f);
                              
                              	while (i > 0.) {
                              		double tmp = modf(i / 10., &i);
                              		printf("%f, %f\n", i, tmp);
                              	}
                              
                              	return 0;
                              }
                              



                              me retourne :


                              340282346638528859811704183484516925440.000000, 0.000000
                              34028234663852885981170418348451692544.000000, 0.000000
                              3402823466385288480057879763104038912.000000, 0.000000
                              340282346638528862763183235278045184.000000, 0.000000
                              34028234663852888120992730898759680.000000, 0.000000
                              3402823466385288812099273089875968.000000, 0.000000
                              340282346638528895621446116573184.000000, 0.000000
                              34028234663852887760704760709120.000000, 0.000000
                              3402823466385288776070476070912.000000, 0.000000
                              340282346638528891680796442624.000000, 0.000000
                              34028234663852890927298248704.000000, 0.000000
                              3402823466385289202680987648.000000, 0.000000
                              340282346638528934011994112.000000, 0.000000
                              34028234663852892542205952.000000, 0.000000
                              3402823466385289468968960.000000, 0.000000
                              340282346638528946896896.000000, 0.000000
                              34028234663852893011968.000000, 0.000000
                              3402823466385289510912.000000, 0.000000
                              340282346638528937984.000000, 0.000000
                              34028234663852892160.000000, 0.000000
                              3402823466385289216.000000, 0.000000
                              340282346638528896.000000, 0.000000
                              34028234663852888.000000, 0.000000
                              3402823466385289.000000, 0.000000
                              340282346638528.000000, 0.875000
                              34028234663852.000000, 0.800781
                              3402823466385.000000, 0.200195
                              340282346638.000000, 0.500000
                              34028234663.000000, 0.799999
                              3402823466.000000, 0.300000
                              340282346.000000, 0.600000
                              34028234.000000, 0.600000
                              3402823.000000, 0.400000
                              340282.000000, 0.300000
                              34028.000000, 0.200000
                              3402.000000, 0.800000
                              340.000000, 0.200000
                              34.000000, 0.000000
                              3.000000, 0.400000
                              0.000000, 0.300000



                              ce qui ne correspond pas vraiment à ce qui est attendu... Il va donc falloir trouver une autre solution pour afficher un flottant.
                              • Partager sur Facebook
                              • Partager sur Twitter
                                18 mai 2012 à 15:32:12

                                Citation

                                Attention qu'avec cette fonction tu écris le byte de poids faible de la variable c, tu écriras donc probablement 0 sur une machine big endian.



                                Ok, merci, je vais corriger ça.

                                Citation

                                De plus, le retour de putchar doit être de type int (retourne EOF en cas d'erreur) et non size_t.



                                Ici, je ne recode pas forcément putchar (d'ailleurs, ça m'étonnerait qu'elle utilise fwrite directement).

                                Citation

                                EDIT : Aussi, les noms d'identificateurs commençant par deux underscores sont réservés et ne doivent par conséquent pas être utilisés ;)



                                En l'occurrence, c'est moi l'implémentation. :D
                                • Partager sur Facebook
                                • Partager sur Twitter
                                Staff désormais retraité.
                                Anonyme
                                  18 mai 2012 à 17:33:04

                                  Citation : Taurre

                                  @informaticienzero: j'ai fait quelque test sur le principe de la fonction que tu m'as passée en lien et malheureusement cela ne fonctionne plus lorsque l'on dépasse des nombres d'une certaine taille. Par exemple, le code suivant :


                                  #include <float.h>
                                  #include <math.h>
                                  #include <stdio.h>
                                  
                                  
                                  int
                                  main(void)
                                  {
                                  	double n = FLT_MAX;
                                  	double i, f;
                                  
                                  	f = modf(n, &i);
                                  	printf("%f, %f\n", i, f);
                                  
                                  	while (i > 0.) {
                                  		double tmp = modf(i / 10., &i);
                                  		printf("%f, %f\n", i, tmp);
                                  	}
                                  
                                  	return 0;
                                  }
                                  



                                  me retourne :


                                  340282346638528859811704183484516925440.000000, 0.000000
                                  34028234663852885981170418348451692544.000000, 0.000000
                                  3402823466385288480057879763104038912.000000, 0.000000
                                  340282346638528862763183235278045184.000000, 0.000000
                                  34028234663852888120992730898759680.000000, 0.000000
                                  3402823466385288812099273089875968.000000, 0.000000
                                  340282346638528895621446116573184.000000, 0.000000
                                  34028234663852887760704760709120.000000, 0.000000
                                  3402823466385288776070476070912.000000, 0.000000
                                  340282346638528891680796442624.000000, 0.000000
                                  34028234663852890927298248704.000000, 0.000000
                                  3402823466385289202680987648.000000, 0.000000
                                  340282346638528934011994112.000000, 0.000000
                                  34028234663852892542205952.000000, 0.000000
                                  3402823466385289468968960.000000, 0.000000
                                  340282346638528946896896.000000, 0.000000
                                  34028234663852893011968.000000, 0.000000
                                  3402823466385289510912.000000, 0.000000
                                  340282346638528937984.000000, 0.000000
                                  34028234663852892160.000000, 0.000000
                                  3402823466385289216.000000, 0.000000
                                  340282346638528896.000000, 0.000000
                                  34028234663852888.000000, 0.000000
                                  3402823466385289.000000, 0.000000
                                  340282346638528.000000, 0.875000
                                  34028234663852.000000, 0.800781
                                  3402823466385.000000, 0.200195
                                  340282346638.000000, 0.500000
                                  34028234663.000000, 0.799999
                                  3402823466.000000, 0.300000
                                  340282346.000000, 0.600000
                                  34028234.000000, 0.600000
                                  3402823.000000, 0.400000
                                  340282.000000, 0.300000
                                  34028.000000, 0.200000
                                  3402.000000, 0.800000
                                  340.000000, 0.200000
                                  34.000000, 0.000000
                                  3.000000, 0.400000
                                  0.000000, 0.300000



                                  ce qui ne correspond pas vraiment à ce qui est attendu... Il va donc falloir trouver une autre solution pour afficher un flottant.



                                  Effectivement. Par contre, ça marche avec des valeurs inférieures. C'est à mon avis un problème innérant à toute fonction qui manipule des nombres.

                                  #include <float.h>
                                  #include <math.h>
                                  #include <stdio.h>
                                  
                                  int main(void)
                                  {
                                  	double m = FLT_MAX;
                                  	double n = strtod("3402823466385288651451515151515251515155151514484141514150114141412141848454545454545454540000000000000000000000.000000", NULL);
                                  
                                  	printf("%lf\n", m);
                                  	printf("%lf\n", n);
                                  
                                  	return 0;
                                  }
                                  


                                  340282346638528860000000000000000000000.000000
                                  2293496.000000


                                  Il y a un maximum pour toutes ces fonctions. Mais je pense que pour un exercice comme celui-là, une version basique est suffisante.
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    18 mai 2012 à 18:21:02

                                    Citation : informaticienzero


                                    Effectivement. Par contre, ça marche avec des valeurs inférieures. C'est à mon avis un problème innérant à toute fonction qui manipule des nombres.



                                    En fait, c'est un problème de précision. Si on suit la norme IEEE 754, un double a une mantisse de 54 bits (en comptant le bit implicite). Or, en l'occurrence, on y stocke 24 bits à 1 et un exposant de 127 (maximum possible pour un float). Ce qui veut dire que les bits de ma mantisse ne peuvent représentés les puissances de 2 que de 127 à 75. Il est donc impossible de représenté un nombre inférieure à 2 x1075. La preuve en image :


                                    #include <float.h>
                                    #include <math.h>
                                    #include <stdio.h>
                                    
                                    
                                    int
                                    main(void)
                                    {
                                    	double n = FLT_MAX;
                                    
                                    	printf("%f\n", n);
                                    	printf("%f\n", n + pow(2., 75));
                                    	printf("%f\n", n + pow(2., 74));
                                    	return 0;
                                    }
                                    



                                    340282346638528859811704183484516925440.000000
                                    340282346638528897590636046441678635008.000000
                                    340282346638528859811704183484516925440.000000


                                    Pour 0.4 ce n'est donc même pas la peine d'en parler :-°
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    Anonyme
                                      18 mai 2012 à 18:23:56

                                      Je vais me renseigner sur les flottants, le sujet à vraiment l'air passionnant. :)

                                      En attendant, une simple version de la fonction suffira puisque en pratique on ne peut pas convertir tous les nombres que l'on veut.
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        18 mai 2012 à 18:25:19

                                        Citation : Taurre

                                        ... J'avoue que j'ai bon y réfléchir je ne vois pour l'instant pas comment faire cela. Je serais curieux de savoir comment ils s'en sortent à Epitech par exemple :)


                                        Pour parler franchement, la plupart des gens ne pensent pas à la manière dont cela est stocké, et vont partir de leur postulat que c'est en base 10, et donc l'afficher à base de multiplications successives par 10.
                                        Très peu se servent de la mantisse et de l'exponentiation pour écrire leur résultat.
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          18 mai 2012 à 18:43:20

                                          Surtout que le %f est considere comme un petit bonus dans notre sujet.
                                          Perso j'avais fait ça très simplement hein.

                                          le %f par defaut est un: %.6f

                                          Donc suffit de faire:

                                          putnbr((int)mon_float);
                                          if (precision)
                                          {
                                            putchar('.');
                                            putnbr((int)((mon_float - (int)mon_float) * pow(10, precision)));
                                          }
                                          


                                          (int)3.14159265                               // -> 3
                                          3.14159265 - (int)3.14159265                  // -> 0.14159265
                                          (3.14159265 - (int)3.14159265) * 10^6         // -> 141592.65
                                          (int)((3.14159265 - (int)3.14159265) * 10^6)  // -> 141592
                                          

                                          Et je crois que ça marche.

                                          M'enfin le vrai printf lui, gère ce genre de chose par exemple: %.25f contrairement a mon truc qui va bugger complètement :S
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            18 mai 2012 à 23:36:05

                                            Mais la représentation du nombre en base 10 est approximative, et tu peux donc avoir quelques erreurs (de l'ordre de 10-6).
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              18 mai 2012 à 23:50:49

                                              Citation : entwanne

                                              Mais la représentation du nombre en base 10 est approximative, et tu peux donc avoir quelques erreurs (de l'ordre de 10-6).



                                              C'est néanmoins celle qui est demandée par la norme, et donc par l'exercice. C'est tout de suite plus dur de lire du flottant en hexadécimal. ^^
                                              Puis bon, il y a déjà des problèmes de précisions inhérents à la représentation flottante, on sait que toute manipulation de ces représentations est sujette à ce type de problèmes. On prend le risque. :)
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                              J'ai déménagé sur Zeste de savoir — Ex-manager des modérateurs.
                                              Anonyme
                                                18 mai 2012 à 23:57:25

                                                C'est vrai que je devrais le préciser, pour cet exercice je pense que la gestion pour la base 10 est suffisante, bien qu'il y ait aussi l'hexadécimal avec le C99.
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  19 mai 2012 à 8:20:54

                                                  Citation : GuilOooo

                                                  Citation : entwanne

                                                  Mais la représentation du nombre en base 10 est approximative, et tu peux donc avoir quelques erreurs (de l'ordre de 10-6).



                                                  C'est néanmoins celle qui est demandée par la norme, et donc par l'exercice. C'est tout de suite plus dur de lire du flottant en hexadécimal. ^^
                                                  Puis bon, il y a déjà des problèmes de précisions inhérents à la représentation flottante, on sait que toute manipulation de ces représentations est sujette à ce type de problèmes. On prend le risque. :)


                                                  Oui, bien sûr, je voulais simplement dire qu'il était préférable de recalculer cette approximation à la main, plutôt que de se baser sur une multiplication du nombre par une puissance de 10, qui elle apporte des imprécisions.
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    19 mai 2012 à 11:25:37

                                                    Citation : entwanne


                                                    Pour parler franchement, la plupart des gens ne pensent pas à la manière dont cela est stocké, et vont partir de leur postulat que c'est en base 10, et donc l'afficher à base de multiplications successives par 10.
                                                    Très peu se servent de la mantisse et de l'exponentiation pour écrire leur résultat.



                                                    Citation : Mr21


                                                    Surtout que le %f est considere comme un petit bonus dans notre sujet.
                                                    Perso j'avais fait ça très simplement hein.

                                                    le %f par defaut est un: %.6f

                                                    Donc suffit de faire:

                                                    putnbr((int)mon_float);
                                                    if (precision)
                                                    {
                                                      putchar('.');
                                                      putnbr((int)((mon_float - (int)mon_float) * pow(10, precision)));
                                                    }
                                                    




                                                    Mmh... Ok, on ne vous parle donc pas de la représentation des flottants et on vous laisse proposer une solution qui ne fonctionne que sur un certain intervalle de nombre.

                                                    Citation : Mr21


                                                    M'enfin le vrai printf lui, gère ce genre de chose par exemple: %.25f contrairement a mon truc qui va bugger complètement :S



                                                    Effectivement, mais même avec la précision par défaut il y a déjà un risque d'integer overflow, avec cette instruction :

                                                    putnbr((int)mon_float);
                                                    


                                                    étant donné qu'un float peut stocker un nombre allant jusqu'à 1 x1037 (suivant la norme C).
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                    Anonyme
                                                      19 mai 2012 à 12:02:44

                                                      Je ne suis pas convaincu par l'exercice… après tout on le trouve déjà dans le K&R non ?
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        19 mai 2012 à 12:16:16

                                                        On attend donc TON code (et non celui du K&R ou autre). ;)
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          19 mai 2012 à 12:16:51

                                                          Tu parles de la fonction `minprintf' que l'on trouve dans le livre ? Si oui, c'est quand même assez réducteur (en plus, `printf' est utilisé dans la fonction). Du moins, dans mon édition.
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                          Staff désormais retraité.
                                                          Anonyme
                                                            19 mai 2012 à 12:22:36

                                                            C'est possible, je ne m'en souviens plus très bien pour être honnête.
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter
                                                              19 mai 2012 à 12:41:19

                                                              Discuter sur la pertinence d'un exercice est une chose, poster pour ne rien dire en est une autre. Attention au flood.
                                                              • Partager sur Facebook
                                                              • Partager sur Twitter
                                                              J'ai déménagé sur Zeste de savoir — Ex-manager des modérateurs.

                                                              [Défis]#11 : zPrintf

                                                              × 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