Like Tree3Likes

Atof with scientific notation

This is a discussion on Atof with scientific notation within the C Programming forums, part of the General Programming Boards category; Good afternoon. I'm trying to code a program which converts a string in a double and in a string again ...

  1. #1
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193

    Question Atof with scientific notation

    Good afternoon. I'm trying to code a program which converts a string in a double and in a string again but with scientific notation.

    The exercise is from KnR:

    Extend atof to handle scientific notation of the form 123.45e-6 where a floating-point number may be followed by e or E and an optionally signed exponent.

    What I want to do, despite of what the exercise mentioned, is convert something like

    450 to 4.50e+2 and 0.05 to 5.0e-2

    that's why I thought I had to convert the double into a string again. To put the "e-2" as a string concatenated with the value.

    In addiction to that, I wonder if I can write char* notation like I wrote in the code. Because I don't want each char separated by index.

    conversion.h

    Code:
     
    void itob(int, char*, int);
    char* Atof(char*);
    atof.c

    Code:
     
    /* atof: convert string s in scientific notation double */
    
    #include <ctype.h> 
    #include <string.h>
    
    #include "../Headers/conversion.h"
    
    
    char* Atof(char* s) 
    { 
       double val, power; 
       int i, sign, npow, dotlocation;
       char* notation, strval, strsci, strnpow;
       
       for(i = 0; isspace(s[i]); i++) 
       ;
       sign = (s[i] == '-') ? -1 : 1;
       if(s[i] == '+' || s[i] == '-') 
         i++; 
       for(val = 0.0; isdigit(s[i]); i++) 
         val = 10.0 * val + (s[i] - '0');            
       if(s[i] == '.') 
       {  
         dotlocation = i;
         i++; 
       }  
       for(power = 1.0, npow = 0; isdigit(s[i]); i++) 
       {  
         val = 10.0 * val + (s[i] - '0');
         power *= 10.0;   
         npow++;  
       }
       
       val = sign * val / power;
       strval = val + '0';
       strnpow = npow + '0';
       
       if(npow > 0 && s[dotlocation - 1] != '0') 
         strsci = "e+" + strnpow + '0'; 
         
       if(npow > 0 && s[dotlocation - 1] == '0') 
         strsci = "e-" + strnpow + '0';
          
       notation = strcat(strval, strsci);
       ++*notation = '\0'; 
       return notation;         
    }
    mainatof.c

    Code:
     
    #include <stdio.h> 
    #include <stdlib.h> 
    
    #include "Headers/conversion.h"
    #include "Conversion/atof.c"
    #include "Validation/isanumber.c"
    
    #ifndef MAXSIZE 
      #define MAXSIZE 1000 
    #endif   
    
    #ifndef SCIENTIFIC 
      #define SCIENTIFIC 4
    #endif
    
    int main(void) 
    { 
      char strnum[MAXSIZE];
      char* notation;
      double d; 
      
      do { 
      printf("Please enter a double: ");       
      fgets(strnum, sizeof(strnum), stdin);
      }while(!isanumber(strnum));
      
      notation = Atof(strnum);
      printf("The double value in scientific notation is %s\n", notation);
      
      return 0;    
    }
    I have some warnings and that error saying the value wasn't assigned to a variable.

    Code:
     
    
    In file included from mainatof.c:5:0:
    Conversion/atof.c: In function ‘Atof’:
    Conversion/atof.c:39:13: warning: assignment makes integer from pointer without a cast [enabled by default]
    Conversion/atof.c:42:13: warning: assignment makes integer from pointer without a cast [enabled by default]
    Conversion/atof.c:44:4: warning: passing argument 1 of ‘strcat’ makes pointer from integer without a cast [enabled by default]
    /usr/include/string.h:136:14: note: expected ‘char * __restrict__’ but argument is of type ‘char’
    Conversion/atof.c:44:4: warning: passing argument 2 of ‘strcat’ makes pointer from integer without a cast [enabled by default]
    /usr/include/string.h:136:14: note: expected ‘const char * __restrict__’ but argument is of type ‘char’
    Conversion/atof.c:45:18: error: lvalue required as left operand of assignment

  2. #2
    SAMARAS std10093's Avatar
    Join Date
    Jan 2011
    Location
    Nice, France
    Posts
    2,694
    You are in C.
    You can not say
    Code:
    strsci = "e+" + strnpow + '0';
    Use strcat for this....

  3. #3
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193
    Code:
     strsci = strcat("e+",strnpow);
    Conversion/atof.c:39:6: warning: passing argument 2 of ‘strcat’ makes pointer from integer without a cast [enabled by default]

    why did I get pointer from integer if strnpow is npow (an integer) added to '0' to (turn into a string?).

  4. #4
    Registered User
    Join Date
    Nov 2011
    Location
    Douala, Cameroon
    Posts
    194
    it would make us see better if you could add more comments to the code cuz this will go a long way in dissecting the code.

  5. #5
    SAMARAS std10093's Avatar
    Join Date
    Jan 2011
    Location
    Nice, France
    Posts
    2,694
    Quote Originally Posted by thames View Post

    why did I get pointer from integer if strnpow is npow (an integer) added to '0' to (turn into a string?).
    Because npow is an integer!
    Code:
    strnpow = npow + '0';
    What do you expect this to result in?
    Check itoa .

    Tip : Eliminate errors and warning that compiler shows top down, because the ones that are not in top might be result of the ones that are on top

  6. #6
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193
    it would make us see better if you could add more comments to the code cuz this will go a long way in dissecting the code.
    Sorry for that. From now on, I'll comment the codes with certain level of complexity.

    Because npow is an integer!
    I thought I could do that because of itoa's code snippet:

    Code:
     
    do { 
        s[i++] = abs(n % 10) + '0';
       } while( (n /= 10) > 0);
    but you made clear to me that just works for a digit and not for a number.

  7. #7
    Registered User whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    7,762
    strcat is being used incorrectly. It appends the second argument to the first, so the first argument must be writable.
    strcat also doesn't work on unititialized char pointers, they have to point to good memory.

  8. #8
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193
    Now I'm only testing numbers like 0.05.

    Code:
    #include "../Headers/conversion.h"
    #include <stdlib.h>
    
    void itoa(int n, char* s) 
    { 
       int sign, i;
       i = 0;
       
       if( (sign = n) < 0)     /* record sign */
        n = -n;   /* turn n positive */
       do { 
        s[i++] = abs(n % 10) + '0';
       } while( (n /= 10) > 0);
       if(sign < 0) 
       { 
         s[i++] = '-';   
       }
       
       s[i] = '\0'; 
    }
    Code:
     
    #include <ctype.h>
    
    #include "../Headers/validation.h"
    
    int isanumber(char* s) { 
      
      int i = 0; 
      
      while(s[i] != '\n') 
      { 
         if(isalpha((unsigned char) s[i]) || isblank( (unsigned char) s[i]) )
           break;
         
         i++;    
      }        
      
      if(s[i] == '\n')
        return 1; 
      return 0;            
    }
    Code:
    #include <string.h>
    
    #include "../Headers/strings.h"
    
    void reverse(char* s, char* reversed) 
    { 
      int i, j;
      
      for(i = strlen(s) - 1, j = 0; i >= 0; i--, j++) 
       reversed[j] = s[i];      
      
      reversed[j] = '\0';
    }
    Code:
     
    
    #include <ctype.h>
    #include <string.h>
    
    #include "../Headers/conversion.h"
    #include "../Headers/strings.h"
    
    #ifndef MAXSIZE 
      #define MAXSIZE 1000
    #endif  
     
    /* atof: convert string s in scientific notation double */
    
    char* Atof(char* s)
    {
       double val, power;
       int i, sign, dotLocation, nPlaces;
       char* notation;
       
       /* (itoa returns the string from the end to the beginning, i.e. inverted) */
       char revstrval[MAXSIZE]; 
       char revstrnplaces[MAXSIZE];
       
       /* the correct order of the string representation of the numbers */
       char straightstrval[MAXSIZE]; 
       char straightstrnplaces[MAXSIZE];
       
       dotLocation = nPlaces = 0;
       
       /* first part: get a double from the string */
       
       /* while there is a space, keep iterating */
       for(i = 0; isspace(s[i]); i++) 
       ; 
       
       sign = (s[i] == '-') ? -1 : 1; 
       
       /* if there is a sign inside the array, just ignore it */
       if(s[i] == '+' || s[i] == '-') 
         i++; 
       
       /* the next block converts the string to a double with the proper sign */ 
       /* ------------------------------------------------- */
        
       for(val = 0.0; isdigit(s[i]); i++) 
         val = 10.0 * val + (s[i] - '0');
       if(s[i] == '.') 
       {  
         dotLocation = i;
         i++;
       }   
       for(power = 1.0; isdigit(s[i]); i++)
       { 
         val = 10.0 * val + (s[i] - '0');
         power *= 10.0;
       } 
        
       val = sign * val / power;     
       
       /* ------------------------------------------------- */
       
       /* second part: write double in scientific notation */
       
       /* count the number of places starting from the first digit after the dot */
       for(i = s[dotLocation] + 1; s[i] != '\0'; i++) 
          nPlaces++;
       
       /* verify if first digit is zero and make sure there is, at least, one
        * place (for numbers like 0.05) */
       
       if(val / 1 == 0 && power > 1.0)
       { 
          val *= power;
          
          itoa(val, revstrval);
          itoa(nPlaces, revstrnplaces);
          
          reverse(revstrval, straightstrval);
          reverse(revstrnplaces, straightstrnplaces);
          
          notation = strcat(straightstrval, "e-");
          notation = strncat(notation, straightstrnplaces, MAXSIZE);
       } 
       
       /* verify if first digit is different from zero and make sure there is, at least, one
        * place (for numbers like 125.5) */
       
       else { 
           
           
       }               
                      
       return notation;      
    }
    Code:
    #include <stdio.h>
    #include <string.h>
    
     #include "Headers/conversion.h"
    #include "Headers/validation.h"
     
    #ifndef MAXSIZE
      #define MAXSIZE 1000
    #endif  
     
    int main(void)
    {
      char strnum[MAXSIZE];
      char notation[MAXSIZE];
      
      do {
      printf("Please enter a double: ");      
      fgets(strnum, sizeof(strnum), stdin);
      }while(!isanumber(strnum));
       
      strcpy(notation, Atof(strnum));
      printf("The double value in scientific notation is %s\n", notation);
       
      return 0;   
    }
    Code:
      gcc -g -Wall mainatof.c Conversion/atof.c Strings/reverse.c Conversion/itoa.c Validation/isanumber.c -o mainatof
      ./mainatof
      Please enter a double: 0.05
      Segmentation fault
    Code:
     valgrind --tool=memcheck --leak-check=full ./mainatof
    ==5566== Memcheck, a memory error detector
    ==5566== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
    ==5566== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
    ==5566== Command: ./mainatof
    ==5566== 
    Please enter a double: 0.05
    ==5566== Conditional jump or move depends on uninitialised value(s)
    ==5566==    at 0x400A3C: Atof (atof.c:64)
    ==5566==    by 0x40075F: main (mainatof.c:21)
    ==5566== 
    ==5566== Use of uninitialised value of size 8
    ==5566==    at 0x4C2D007: strcpy (mc_replace_strmem.c:438)
    ==5566==    by 0x400774: main (mainatof.c:21)
    ==5566== 
    ==5566== Invalid read of size 1
    ==5566==    at 0x4C2D007: strcpy (mc_replace_strmem.c:438)
    ==5566==    by 0x400774: main (mainatof.c:21)
    ==5566==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
    ==5566== 
    ==5566== 
    ==5566== Process terminating with default action of signal 11 (SIGSEGV)
    ==5566==  Access not within mapped region at address 0x0
    ==5566==    at 0x4C2D007: strcpy (mc_replace_strmem.c:438)
    ==5566==    by 0x400774: main (mainatof.c:21)
    ==5566==  If you believe this happened as a result of a stack
    ==5566==  overflow in your program's main thread (unlikely but
    ==5566==  possible), you can try to increase the size of the
    ==5566==  main thread stack using the --main-stacksize= flag.
    ==5566==  The main thread stack size used in this run was 8388608.
    ==5566== 
    ==5566== HEAP SUMMARY:
    ==5566==     in use at exit: 0 bytes in 0 blocks
    ==5566==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
    ==5566== 
    ==5566== All heap blocks were freed -- no leaks are possible
    ==5566== 
    ==5566== For counts of detected and suppressed errors, rerun with: -v
    ==5566== Use --track-origins=yes to see where uninitialised values come from
    ==5566== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
    Segmentation fault

  9. #9
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    In your Atof():
    Code:
    for(i = s[dotLocation] + 1; s[i] != '\0'; i++) 
        nPlaces++;
    What's the value of the expression "s[dotLocation]"?

    Bye, Andreas
    thames likes this.

  10. #10
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193
    I decided, for now, to put every necessary function inside the main source because is easier to handle everything that way. Why is 0.050000000000000003 the value of val when I input 0.05 as a string to be converted into a double?

    Code:
     
     #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #include <stdlib.h>
    
    #ifndef MAXSIZE
      #define MAXSIZE 1000
    #endif  
     
    void reverse(char* s, char* reversed) 
    { 
      int i, j;
      
      for(i = strlen(s) - 1, j = 0; i >= 0; i--, j++) 
       reversed[j] = s[i];      
      
      reversed[j] = '\0';
    }
    
    void itoa(int n, char* s) 
    { 
       int sign, i;
       i = 0;
       
       if( (sign = n) < 0)     /* record sign */
        n = -n;   /* turn n positive */
       do { 
        s[i++] = abs(n % 10) + '0';
       } while( (n /= 10) > 0);
       if(sign < 0) 
       { 
         s[i++] = '-';   
       }
       
       s[i] = '\0'; 
    }
    
    int isanumber(char* s) { 
      
      int i = 0; 
      
      while(s[i] != '\n') 
      { 
         if(isalpha((unsigned char) s[i]) || isblank( (unsigned char) s[i]) )
           break;
         
         i++;    
      }        
      
      if(s[i] == '\n')
        return 1; 
      return 0;            
    }
    
    char* Atof(char* s)
    {
       double val, power;
       int i, sign, afterDot, nPlaces;
       char* notation;
       
       /* (itoa returns the string from the end to the beginning, i.e. inverted) */
       char revstrval[MAXSIZE]; 
       char revstrnplaces[MAXSIZE];
       
       /* the correct order of the string representation of the numbers */
       char straightstrval[MAXSIZE]; 
       char straightstrnplaces[MAXSIZE];
       
       afterDot = 0;
       
       /* first part: get a double from the string */
       
       /* while there is a space, keep iterating */
       for(i = 0; isspace(s[i]); i++) 
       ; 
       
       sign = (s[i] == '-') ? -1 : 1; 
       
       /* if there is a sign inside the array, just ignore it */
       if(s[i] == '+' || s[i] == '-') 
         i++; 
       
       /* the next block converts the string to a double with the proper sign */ 
       /* ------------------------------------------------- */
        
       for(val = 0.0; isdigit(s[i]); i++) 
         val = 10.0 * val + (s[i] - '0');
       if(s[i] == '.') 
       {  
         afterDot = i + 1;
         i++;
       }   
       for(power = 1.0; isdigit(s[i]); i++)
       { 
         val = 10.0 * val + (s[i] - '0');
         power *= 10.0;
       } 
        
       val = sign * val / power;     
       
       /* ------------------------------------------------- */
       
       /* second part: write double in scientific notation */
       
       /* count the number of places starting from the first digit after the dot */
       for(i = afterDot, nPlaces = 0; s[i] != '\n'; i++, nPlaces++)
       ; 
         
       /* verify if first digit is zero and make sure there is, at least, one
        * place (for numbers like 0.05) */
       
       if(val / 1 == 0 && power > 1.0)
       { 
          val *= power;
          
          itoa(val, revstrval);
          itoa(nPlaces, revstrnplaces);
          
          reverse(revstrval, straightstrval);
          reverse(revstrnplaces, straightstrnplaces);
          
          notation = strcat(straightstrval, "e-");
          notation = strncat(notation, straightstrnplaces, MAXSIZE);
       } 
       
       /* verify if first digit is different from zero and make sure there is, at least, one
        * place (for numbers like 125.5) */
       
       else { 
           
           
       }               
                      
       return notation;      
    }
    
    int main(void)
    {
      char strnum[MAXSIZE];
      char notation[MAXSIZE];
      
      do {
      printf("Please enter a double: ");      
      fgets(strnum, sizeof(strnum), stdin);
      }while(!isanumber(strnum));
       
      strcpy(notation, Atof(strnum));
      printf("The double value in scientific notation is %s\n", notation);
       
      return 0;   
    }
    Code:
    ethereal@laerehte ~/C/Conversions $ gdb -q scinotation
    Reading symbols from /home/ethereal/C/Conversions/scinotation...done.
    (gdb) break 106
    Breakpoint 1 at 0x400af7: file scinotation.c, line 106.
    (gdb) run
    Starting program: /home/ethereal/C/Conversions/scinotation 
    Please enter a double: 0.5
    
    Breakpoint 1, Atof (s=0x7fffffffdee0 "0.5\n") at scinotation.c:106
    106       for(i = afterDot, nPlaces = 0; s[i] != '\n'; i++, nPlaces++)
    (gdb) print val
    $1 = 0.5
    (gdb) cont
    Continuing.
    
    Program received signal SIGSEGV, Segmentation fault.
    __strcpy_ssse3 () at ../sysdeps/x86_64/multiarch/strcpy-ssse3.S:44
    44    ../sysdeps/x86_64/multiarch/strcpy-ssse3.S: No such file or directory.
    (gdb) run
    The program being debugged has been started already.
    Start it from the beginning? (y or n) y
    Starting program: /home/ethereal/C/Conversions/scinotation 
    Please enter a double: 0.05
    
    Breakpoint 1, Atof (s=0x7fffffffdee0 "0.05\n") at scinotation.c:106
    106       for(i = afterDot, nPlaces = 0; s[i] != '\n'; i++, nPlaces++)
    (gdb) print val
    $2 = 0.050000000000000003
    (gdb) cont
    Continuing.
    
    Program received signal SIGSEGV, Segmentation fault.
    __strcpy_ssse3 () at ../sysdeps/x86_64/multiarch/strcpy-ssse3.S:44
    44    ../sysdeps/x86_64/multiarch/strcpy-ssse3.S: No such file or directory.
    (gdb)
    Last edited by thames; 11-18-2012 at 08:00 AM.

  11. #11
    Registered User whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    7,762
    It's pretty damn close.

    The only time you get an exact floating point number is when the number is a modal number: A real number that can be exactly represented in the number of bits a double has. I'll give you a real world example. 0.2 is a real number that does not get represented exactly in binary, instead you end up with the binary version of 0.1999999... So, basically, if it's not a modal number you are going to live with a binary approximation of the real number.

  12. #12
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193
    I solved the final problem (convert a number like 125.5 to 1.255e+2) using sprintf. However my array got a lot of junk.

    edit:

    I still didn't fix the output of a number like -125.5

    Code:
     
    gdb -q scinotation
    Reading symbols from /home/ethereal/C/Conversions/scinotation...done.
    (gdb) break 150
    Breakpoint 1 at 0x400e0f: file scinotation.c, line 150.
    (gdb) run
    Starting program: /home/ethereal/C/Conversions/scinotation 
    Please enter a double: 125.5
    
    Breakpoint 1, Atof (s=0x7fffffffdee0 "125.5\n") at scinotation.c:150
    150          itoa(nCardinality, revncardinality);
    (gdb) print straightstrval
    $1 = "1.255000", '\000' <repeats 400 times>, "t:\336\367\377\177\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\003\000\000\000\000\000\000\000\300\251\377\367\377\177\000\000\207\360\226|\000\000\000\000\236B\336\367\377\177\000\000\000\000\000\000\000\000\000\000\a\000\000\000\000\000\000\000\240\326\377\377\377\177\000\000\377\377\377\377\000\000\000\000x\354\241\367\377\177\000\000\250\354\241\367\377\177\000\000p\326\377\377\377\177\000\000\000\000\000\000\000\000\000\000ظ\242\367\377\177", '\000' <repeats 18 times>, "Ȫ\377\367\377\177\000\000\300\244\377\367\377\177\000\000%Ϣ\367\377\177\000\000\370\271\242\367\377\177\000\000ظ\242\367\377\177\000\000\000\000\000\000\001\000\000\000\202\b\000\000\001", '\000' <repeats 11 times>, "\030\250\377\367\377\177\000\000\340\326\377\377\377\177\000\000\207\360\226|\000\000\000\000Ȫ\377\367\377\177\000\000\000\327\377\377\377\177\000\000\300\244\377\367\377\177\000\000#E\336\367\377\177\000\000\000\000\000\000\000\000\000\000Ȫ\377\367\377\177\000\000\001", '\000' <repeats 15 times>...
    (gdb) cont
    Continuing.
    The double value in scientific notation is 1.255000e+2
    [Inferior 1 (process 2966) exited normally]
    how's that?
    Last edited by thames; 11-18-2012 at 06:05 PM.

  13. #13
    Registered User whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    7,762
    The exercise is from KnR:

    Extend atof to handle scientific notation of the form 123.45e-6 where a floating-point number may be followed by e or E and an optionally signed exponent.

    What I want to do, despite of what the exercise mentioned, is convert something like

    450 to 4.50e+2 and 0.05 to 5.0e-2
    My two cents are that you would have a much easier time doing what you want to do if you looked at the binary representation of floating point numbers. The conversion from binary format to a decimal format should be relatively straightforward, unlike with string input. With string input you have to deal with a myriad of cases, meanwhile in binary format there are only a few formats I've remotely heard of, and IEEE standard floating point numbers are also extremely common, so it serves as a good starting point. Any decent display method probably does not do a ton of slow string manipulations.

    What you are turning atof() into is nothing like atof() as well... it's supposed to ASCII to floating point. Meanwhile atof() implementations do not interpret scientific notation. I can understand where KnR is coming from, extending atof to handle this, and expecting you to return a value, but you've changed it so that we put in ASCII and we get more ASCII out. You will still learn a lot about strings, but atof() this is not.
    thames likes this.

  14. #14
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193
    what I wrote so far.

    I almost got a scientific notation:

    Code:
     
    Please enter a double: -0.00012345
    The double value in scientific notation is -12345e-8
    [code]

    the code so far:

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #include <stdlib.h>
    #include <math.h>
    
    #ifndef MAXSIZE
      #define MAXSIZE 1000
    #endif  
     
    void reverse(char* s, char* reversed) 
    { 
      int i, j;
      
      for(i = strlen(s) - 1, j = 0; i >= 0; i--, j++) 
       reversed[j] = s[i];      
      
      reversed[j] = '\0';
    }
    
    void itoa(int n, char* s) 
    { 
       int sign, i;
       i = 0;
       
       if( (sign = n) < 0)     /* record sign */
        n = -n;   /* turn n positive */
       do { 
        s[i++] = abs(n % 10) + '0';
       } while( (n /= 10) > 0);
       if(sign < 0) 
       { 
         s[i++] = '-';   
       }
       
       s[i] = '\0'; 
    }
    
    int isanumber(char* s) { 
      
      int i = 0; 
      
      while(s[i] != '\n') 
      { 
         if(isalpha((unsigned char) s[i]) || isblank( (unsigned char) s[i]) )
           break;
         
         i++;    
      }        
      
      if(s[i] == '\n')
        return 1; 
      return 0;            
    }
    
    char* Atof(char* s)
    {
       double val, power, cardinality;
       int j, i, sign, afterDot, nPlaces, firstDigit, nCardinality;
       char* notation;
       
       /* (itoa returns the string from the end to the beginning, i.e. inverted) */
       char revstrval[MAXSIZE]; 
       char revstrnplaces[MAXSIZE];
       char revncardinality[MAXSIZE];
       
       /* the correct order of the string representation of the numbers */
       char straightstrval[MAXSIZE]; 
       char straightstrnplaces[MAXSIZE];
       char straightncardinality[MAXSIZE];
       
       afterDot = 0;
       nCardinality = -1;
       
       /* first part: get a double from the string */
       
       /* while there is a space, keep iterating */
       for(i = 0; isspace(s[i]); i++) 
       ; 
       
       sign = (s[i] == '-') ? -1 : 1; 
       
       /* if there is a sign inside the array, just ignore it */
       if(s[i] == '+' || s[i] == '-') 
         i++; 
       
       /* the next block converts the string to a double with the proper sign */ 
       /* ------------------------------------------------- */
        
       for(val = 0.0; isdigit(s[i]); i++) 
         val = 10.0 * val + (s[i] - '0');
       if(s[i] == '.') 
       {  
         afterDot = i + 1;
         i++;
       }   
       for(power = 1.0; isdigit(s[i]); i++)
       { 
         val = 10.0 * val + (s[i] - '0');
         power *= 10.0;
       } 
        
       val = sign * val / power;     
       
       /* ------------------------------------------------- */
       
       /* second part: write double in scientific notation */
       
       /* count the number of places starting from the first digit after the dot */
       for(i = afterDot, nPlaces = 0; s[i] != '\n'; i++, nPlaces++)
       ; 
         
        /* get the first digit */
        
        for(i = 0; !isdigit(s[i]); i++)
        ;   
          if(isdigit(s[i]))
            firstDigit = i;
            
        
        /* ignore the sign */
        
        for(i = 0; s[i] != '.'; i++) 
         if(s[i] == '-' || s[i] == '+') 
         { 
           i++;
           break;
         }  
              
        /* get the cardinality of the number */
        
        for(j = i; s[j] != '.'; j++, nCardinality++) 
        ;
        cardinality = pow(10.0, nCardinality);  
                     
            
       /* verify if first digit is zero and make sure there is, at least, one
        * place (for numbers like 0.05) */
       
       if(s[firstDigit] == '0' && power > 1.0)
       { 
          val *= power;
          
          /* get the string representation of value and of the places */
          
          itoa(val, revstrval);
          itoa(nPlaces, revstrnplaces);
          
          reverse(revstrval, straightstrval);
          reverse(revstrnplaces, straightstrnplaces);
          notation = strcat(straightstrval, "e-");
          notation = strncat(notation, straightstrnplaces, MAXSIZE);
       } 
       
       /* verify if first digit is different from zero and make sure there is, at least, one
        * place (for numbers like 125.5) */
       
       else if(s[firstDigit] != '0' && power > 1.0) 
       {      
          val /= cardinality;
          
          sprintf(straightstrval, "%f", val);
          itoa(nCardinality, revncardinality);
          reverse(revncardinality, straightncardinality);
          notation = strcat(straightstrval, "e+");
          notation = strncat(notation, straightncardinality, MAXSIZE);
       }               
                      
       return notation;      
    }
    
    int main(void)
    {
      char strnum[MAXSIZE];
      char notation[MAXSIZE];
      
      do {
      printf("Please enter a double: ");      
      fgets(strnum, sizeof(strnum), stdin);
      }while(!isanumber(strnum));
       
      strcpy(notation, Atof(strnum));
      printf("The double value in scientific notation is %s\n", notation);
       
      return 0;   
    }

  15. #15
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193
    My two cents are that you would have a much easier time doing what you want to do if you looked at the binary representation of floating point numbers.
    I will search for it.

    edit:

    Can you show me a good link about the algorithm process?

    but atof() this is not
    I see, you're completely right.
    Last edited by thames; 11-18-2012 at 07:49 PM.

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Scientific notation
    By manzoor in forum C++ Programming
    Replies: 6
    Last Post: 11-13-2007, 09:46 AM
  2. output is in scientific notation
    By scwizzo in forum Windows Programming
    Replies: 2
    Last Post: 09-18-2007, 11:37 AM
  3. Scientific notation
    By Lionmane in forum C Programming
    Replies: 9
    Last Post: 06-02-2005, 12:10 AM
  4. Reading scientific notation
    By PunkyBunny300 in forum C Programming
    Replies: 1
    Last Post: 04-24-2003, 10:22 PM
  5. Scientific Notation
    By Unregistered in forum C Programming
    Replies: 2
    Last Post: 02-18-2002, 03:08 PM

Tags for this Thread


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21