Subversion Repositories wimsdev

Rev

Rev 5356 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2. *********************************************************************************
  3. * J.M. Evers 3/2012                                                             *
  4. * This is all amateur scriblings... So no copyrights.                           *
  5. * This source code file, and compiled objects derived from it,                  *
  6. * can be used and distributed without restriction, including for commercial use *
  7. * No warrenty whatsoever                                                        *
  8. *********************************************************************************
  9. syntax number_1 number2 number_3 ... number_n
  10.  
  11. Treats a number as string array : no numerical evaluation !
  12. (pfffff...)
  13.  
  14. example
  15. !exec sigdigits 1.23 1.230 1.2300 1.23e5 1.23*10^5 1.2300e5 01.23*10^5 1.2.3.4
  16. 3,1,2,1,0,1
  17. 4,1,3,1,0,1
  18. 5,1,4,1,0,1
  19. 3,1,2,10,5,1
  20. 3,1,2,10,5,1
  21. 5,1,4,10,5,1
  22. 3,2,2,10,5,0
  23. -1,-1,-1,-1,-1,-1
  24.  
  25. result is
  26. 1 line per input number
  27. 6 items per line:
  28.  
  29. item 1) real number of significant digits in number_x (eg without leading zeros)
  30.  
  31. item 2) number of digits left from decimal point or if no decimals: total number of digits (length)
  32.  
  33. item 3) number of digits right from decimal point
  34.  
  35. item 4) exponent base (if not present : 1)
  36.  
  37. item 5) exponent (if not present : 0)
  38.  
  39. item 6) indication : is the number correctly written ?  1 or 0  ( 000.1 is not correct...)
  40.         scientiffic: [1-9.*] *10^exp : 1.2345*10^5 is OK ... 12.345*10^4 or 0.12345*10^6 is "NOK"
  41.         a*10^b  : 1 <= a <= 9
  42.  
  43. remarks:
  44. - exponent: any other base will be tolerated : 4*7^5  base=7 exponent=5 -> 1,0,1,0,7,5,1
  45. - if number is 'nonsense' : -1,-1,-1,-1,-1 (1.23.4567  10^1.23.4 ; number will produce NaN in other math software)
  46.  
  47. ruleset:
  48. 120.2           : 4 significant digits
  49. 120.2000        : 7 significant digits
  50. 0.0000120       : 3 significant digits
  51. scientiffic notation:
  52. 1.202*10^5      : 4 significant digits
  53. 1.20200*10^5    : 6 significant digits
  54.  
  55.  
  56. */
  57.  
  58. #include <stdio.h>
  59. #include <stdlib.h>
  60. #include <string.h>
  61. #define MAX_DIGITS 64
  62. #define MAX_CONV 64
  63.  
  64. void append(char* s, char c){
  65.     int len = strlen(s);
  66.     s[len] = c;
  67.     s[len+1] = '\0';
  68. }
  69.  
  70. int main( int argc , char *argv[]){
  71.     if( argc < 2){
  72.         fprintf(stdout,"syntax error\n");
  73.         exit(0);
  74.     }
  75.     char word[MAX_DIGITS];
  76.     char *input;
  77.     char exp[MAX_DIGITS];
  78.     int cnt,i,ok,length,zeros,sig1,sig2,found_digit,found_point,dec1,pow,found_power,found_multiply,points,base_start,base_end,bracket;
  79.     const char *invalid_characters = "\n\"\',!=ABCDFGHIJKLMNOPQRSTUVWXYZabcdfghijklmnopqrstuvwxyz@#$%&;:~><?/\\|";
  80.     /* Ee +- are allowed : 12.34e+05  12.34e-08  1.234*10^123*/
  81.     cnt = 1;
  82.     input = argv[cnt];
  83.     while( input != NULL){
  84.         if(cnt > MAX_CONV){fprintf(stdout,"error : number of conversions exceeds limit of %d\n",MAX_CONV);return 0;}
  85.         length = strlen(input);
  86.         if( length > MAX_DIGITS){
  87.             fprintf(stdout,"error : number is larger than %d digits\n",MAX_DIGITS);
  88.             return 0;
  89.         }
  90.         /* test for illegal characters */
  91.         while (*input){
  92.             if ( strchr(invalid_characters, *input) ){
  93.                 fprintf(stdout,"error : found illegal character in argument \"%s\" \n",input);
  94.                 return 0;
  95.             }
  96.             input++;
  97.         }
  98.         input = argv[cnt];
  99.         // better way to use strncpy
  100.         strncpy( word, input, MAX_DIGITS - strlen(word)-1);
  101.         // reset
  102.         found_digit = 0;
  103.         found_point = 0;
  104.         found_power = 0;
  105.         bracket = 0;
  106.         found_multiply = 0;
  107.         sig1 = 0; // real significant digits
  108.         sig2 = 0; // integer part [including leading zeros]
  109.         dec1 = 0; // decimal part [including trailing zeros]
  110.         pow = 0; // exponent
  111.         zeros = 0; // leading or trailing zeros
  112.         points = 0; // number of points in number...
  113.         exp[0]='\0';
  114.         base_start = 0;
  115.         base_end = 0;
  116.         ok = 0;
  117.         for( i = length - 1 ; i >= 0 ; i--){ // walk from rightside to left through the 'number'
  118.             switch( word[i] ){
  119.                 case '(' : bracket = 1 ;break; //  10^(-4) -> exp= (-4) : remove bracket from exponent.
  120.                 case ')' : bracket = 1 ;break;
  121.                 case '{' : bracket = 1 ;break;
  122.                 case '}' : bracket = 1 ;break;
  123.                 case '[' : bracket = 1 ;break;
  124.                 case ']' : bracket = 1 ;break;
  125.                 case '^' : base_start = i;found_power++;break;
  126.                 case '*' :
  127.                     found_multiply++;
  128.                     if(found_power == 1){
  129.                         base_end = i;
  130.                         if(found_point == 1){points--;found_point = 0;}  // point in exponent... 10^4.5 (hmmm)
  131.                         pow = length - i;
  132.                         sig1 = 0; // reset counting significant digits and all other stuff
  133.                         sig2 = 0;
  134.                         dec1 = 0;
  135.                         found_digit = 0;
  136.                         zeros = 0;
  137.                     }
  138.                     break;
  139.                 case 'e' : if(found_point == 1){points--;found_point = 0;} found_power++;pow = length - i;sig1 = 0;sig2 = 0;dec1 = 0;found_digit = 0;zeros = 0;found_multiply++;break;
  140.                 case 'E' : if(found_point == 1){points--;found_point = 0;} found_power++;pow = length - i;sig1 = 0;sig2 = 0;dec1 = 0;found_digit = 0;zeros = 0;found_multiply++;break;
  141.                 case '0' :
  142.                     if(i == 0){//last char
  143.                         sig1 = sig1 - zeros;
  144.                         sig2++;
  145.                         if(found_power == 1){zeros++;}
  146.                     }
  147.                     else
  148.                     {              
  149.                         // 1.000*10^5 -> 4 sig
  150.                         if( found_point == 0 ){
  151.                             sig1++;
  152.                         }
  153.                         else
  154.                         {
  155.                             sig2++;
  156.                             if( found_digit == 1 ){ sig1++; }
  157.                         }
  158.                         zeros++;
  159.                     }
  160.                     break;
  161.                 case '.' : dec1 = length - i - pow - 1;found_point = 1;points++; break;
  162.                 case '1' : sig1++;if(found_point == 1){sig2++;} found_digit = 1;zeros = 0; break;
  163.                 case '2' : sig1++;if(found_point == 1){sig2++;} found_digit = 1;zeros = 0; break;
  164.                 case '3' : sig1++;if(found_point == 1){sig2++;} found_digit = 1;zeros = 0; break;
  165.                 case '4' : sig1++;if(found_point == 1){sig2++;} found_digit = 1;zeros = 0; break;
  166.                 case '5' : sig1++;if(found_point == 1){sig2++;} found_digit = 1;zeros = 0; break;
  167.                 case '6' : sig1++;if(found_point == 1){sig2++;} found_digit = 1;zeros = 0; break;
  168.                 case '7' : sig1++;if(found_point == 1){sig2++;} found_digit = 1;zeros = 0; break;
  169.                 case '8' : sig1++;if(found_point == 1){sig2++;} found_digit = 1;zeros = 0; break;
  170.                 case '9' : sig1++;if(found_point == 1){sig2++;} found_digit = 1;zeros = 0; break;
  171.                 default :  break;
  172.             }
  173.             if(found_power == 0 && bracket == 0){ append(exp,word[i]); } // maybe a power was used ?
  174.             bracket = 0;
  175.         }
  176.        
  177.         if( found_power > 1 || found_multiply > 1){ // 2*2 10^5^7
  178.             fprintf(stdout,"error \n");
  179.             return 0;
  180.         }
  181.  
  182.         if( points > 1){ // "nonsense" number 1.23.45  or 1.23*10^1.5
  183.             fprintf(stdout,"-1,-1,-1,-1,-1,-1\n");
  184.         }
  185.         else
  186.         {
  187.             // extra check for handling "special cases"
  188.             if(found_point == 1 && found_power == 0 && found_multiply == 0 && word[1] == '.'){ok = 1;}// just a decimal number 0.1233
  189.             else
  190.             if(found_point == 0 && found_power == 0){ sig2 = length;ok = 1; }   // just a number 12345
  191.             else
  192.             if(found_point == 0 && found_multiply == 0 && found_power == 1){ sig1 = 0; sig2 = 0 ; dec1 = 0; }   // 10^5
  193.             else
  194.             if(found_point == 1 && found_multiply == 0 && found_power == 1){ sig1 = 0; sig2 = 0 ; dec1 = 0; }   // 10^5.1
  195.             else
  196.             if(found_point == 0 && found_multiply == 1 && found_power == 1){ dec1 = 0; sig2 = length - zeros - pow;}    // 3*10^5
  197.                
  198.             if( found_power == 1){
  199.                 // find out if scientiffic number is correctly written ; ok=0 -> ok=1
  200.                 // rule [1-9].[0-9]* x10^exp
  201.                 if( word[0] != '0' && word[1] == '.' ){ //  0.120*10^5 => 1.20*10^4
  202.                     ok = 1;
  203.                 }
  204.                 else
  205.                 {
  206.                     if( (word[0] == '-' || word[0] == '+' ) && word[1] != '0' && word[2] == '.' ){
  207.                         ok = 1; // -1.2*10^5
  208.                     }
  209.                     else
  210.                     {
  211.                         if( found_point == 0 && found_multiply == 1 ){
  212.                             if( word[1] == '*' ){ //4*10^5
  213.                                 ok = 1;
  214.                             }
  215.                             else
  216.                             {
  217.                                 if( (word[0] == '-' || word[0] == '+' ) && word[2] == '*'){ //-4*10^5
  218.                                     ok = 1;
  219.                                 }
  220.                             }
  221.                         }
  222.                     }
  223.                 }
  224.                 int len = strlen(exp);// reverse appended char array ... 123+ --> +321
  225.                 char exponent[len];
  226.                 int w = len - 1;
  227.                 for(i = 0 ; i < len ; i++){
  228.                     exponent[i] = exp[w];
  229.                     w--;
  230.                 }
  231.                 exponent[len] = '\0';
  232.                 if(base_start != 0){ // find the base ( default base = 10 )
  233.                     int c = 0;int s;
  234.                     if(base_end == 0){ // 10^5
  235.                         s = 0;
  236.                     }
  237.                     else
  238.                     {
  239.                         s = base_end + 1; // 1.25*10^5
  240.                     }
  241.                     char c_base[base_start - s]; // assign char array of correct size
  242.                     for(i = s ; i < base_start ; i++){
  243.                         c_base[c] = word[i];
  244.                         c++;
  245.                     }
  246.                     c_base[c] = '\0';
  247.                     fprintf(stdout,"%d,%d,%d,%s,%s,%d\n",sig1,sig2,dec1,c_base,exponent,ok);
  248.                 }
  249.                 else
  250.                 { // base = 10 : used 4e+5
  251.                     fprintf(stdout,"%d,%d,%d,10,%s,%d\n",sig1,sig2,dec1,exponent,ok);
  252.                 }
  253.             }
  254.             else
  255.             {   // no exponent : base = '1' exponent = '0'
  256.                 //several possible correct way of writing...
  257.                 if( ok == 0 && (  sig1 == sig2 + dec1 ) ){ ok  = 1; }
  258.                 fprintf(stdout,"%d,%d,%d,1,0,%d\n",sig1,sig2,dec1,ok);
  259.             }
  260.         }
  261.         cnt++;
  262.         input = argv[cnt];
  263.     }
  264.     return 0;
  265. }
  266.