Subversion Repositories wimsdev

Rev

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