Subversion Repositories wimsdev

Rev

Rev 7111 | Rev 15712 | 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 -very- 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.  
  10. WIMS usage:
  11. sci_num = !exec scienceprint number,significance,type
  12.  
  13. number: a number (like 12345 123.45*10^2 123.45E+02)
  14. significance : desired precision (if significance= -1 : "science notation" in name amount of digits)
  15. type (optional args): calc = 0 / html = 1 / latex = 2  / prefix = 3  / mathml = 4
  16.  
  17. default  : calc   notation : 120000,3   -> 1.20*10^5
  18. type = 0 : calc   notation : 120000,3,0 -> 1.20*10^5
  19. type = 1 : html notation   : 120000,3,1 -> 1.20&times;10<sup>5</sup>
  20. type = 2 : latex notation  : 120000,3,2 -> 1.20 \times 10^{5}
  21. type = 3 : prefix-notation : 120000,3,3 -> 120.0 k
  22. type = 3 : if -24 > prefix > 24         -> type = 1 (html)
  23. type = 4 : mathml notation
  24. type = 5 : prefix-notation with words (nano,mega,giga...etc) :120000,3,3 -> 120.0 kilo
  25.  
  26. multiple conversion: use space between arguments
  27. scienceprint 120000,4 122900,5 120036,6,3 --> 120.0*10^3,122.90*10^3,120.036 k
  28.  
  29.  
  30. *********************************************************************************
  31. 16/10/2013
  32. corrected roundoff in case "significance=-1" changed 'factor' from 'int' to 'float'...there must be a better way to do this...
  33. But in numbers > 1000000000000000 there is still a problem, so take care (!)
  34. when there are more than 15 digits in the number (this may vary depending on system / implementations, I guess)
  35. ./scienceprint 901234567890123       ,-1,0 --> 9.01234567890123*10^14
  36. ./scienceprint 9012345678901234      ,-1,0 --> 9.012345678901236*10^15
  37. ./scienceprint 901234567890123*10^70 ,-1,0 --> 9.01234567890123*10^84
  38. ./scienceprint 9012345678901234*10^70,-1,0 --> 9.012345678901227*10^85
  39. *********************************************************************************
  40. 28/9/2013
  41. minor issue:
  42. Added type = 5 : prefix-notation with words (nano,mega,giga...etc)
  43. small correction in roundoff routine when significance > 6 .... pow(10,7) may give problems when stored in (int) integer
  44. *********************************************************************************
  45. 27/9/2013
  46. Correct rounding in stead of truncation...
  47. *********************************************************************************
  48. 18/10/2012 :
  49. Added Mathml output
  50. Added option significance=-1
  51. To be used when there is no significance known ; just tries to print the number in science notation
  52. Using the original amount of digits used in "number" argument
  53. !exec scienceprint 123.445000e+23,-1 --> 1.23445000*10^25
  54. *********************************************************************************
  55. 12/11/2012
  56. Added support for numbers like  12345*10^12
  57. 12345*10^12 --> 12345E12 ---> 1.2345*10^16
  58. *********************************************************************************
  59. 20/6/2012
  60. Corrected significance flaw when using prefixes
  61. Simplified routines
  62. 24  yotta       Y
  63. 21  zetta       Z
  64. 18  exa         E
  65. 15  peta        P
  66. 12  tera        T
  67. 9   giga        G
  68. 6   mega        M
  69. 3   kilo        k
  70. 2   hecto       h
  71. 1   deca        da
  72. -1  deci        d
  73. -2  centi       c
  74. -3  milli       m
  75. -6  micro       µ
  76. -9  nano        n
  77. -12 pico        p
  78. -15 femto       f
  79. -18 atto        a
  80. -21 zepto       z
  81. -24 yocto       y
  82. */
  83. #include <stdio.h>
  84. #include <math.h>
  85. #include <string.h>
  86. #include <stdlib.h>
  87. #define MICRO "µ"
  88. #define MAX_CONV 256
  89. #define MAX_STRING 32
  90. #define PREFIX_START -24
  91. #define PREFIX_END 24
  92.  
  93. char *str_replace ( const char *word, const char *sub_word, const  char *rep_word ){
  94.     if(strlen(word) > MAX_STRING){return NULL;}
  95.     char *part_word = NULL;
  96.     char *new_word = NULL;
  97.     char *old_word = NULL;
  98.     char *head = NULL;
  99.     /* if either sub_word or rep_word is NULL, duplicate word a let caller handle it */
  100.     if ( sub_word == NULL || rep_word == NULL ) return strdup(word);
  101.     new_word = strdup (word);
  102.     head = new_word;
  103.     while ( (part_word = strstr ( head, sub_word ))){
  104.         old_word = new_word;
  105.         new_word = malloc ( strlen ( old_word ) - strlen ( sub_word ) + strlen ( rep_word ) + 1 );
  106.         /*failed to alloc mem, free old word and return NULL */
  107.         if ( new_word == NULL ){
  108.           free (old_word);return NULL;
  109.         }
  110.         memcpy ( new_word, old_word, part_word - old_word );
  111.         memcpy ( new_word + (part_word - old_word), rep_word, strlen ( rep_word ) );
  112.         memcpy ( new_word + (part_word - old_word) + strlen( rep_word ), part_word + strlen ( sub_word ), strlen ( old_word ) - strlen ( sub_word ) - ( part_word - old_word ) );
  113.         memset ( new_word + strlen ( old_word ) - strlen ( sub_word ) + strlen ( rep_word ) , 0, 1 );
  114.         /* move back head right after the last replacement */
  115.         head = new_word + (part_word - old_word) + strlen( rep_word );
  116.         free (old_word);
  117.     }
  118.     return new_word;
  119. }
  120.  
  121. char *printscience(double value, int sig, int format , int cnt ,int size){
  122.     static char *min[] = {"","m",MICRO,"n","p","f","a","z","y"};
  123.     static char *plus[] = {"","k", "M", "G", "T", "P", "E", "Z", "Y" };
  124.     static char *min_word[] = {"","milli","micro","nano","pico","femto","atto","zepto","yocto"};
  125.     static char *plus_word[] = {"","kilo", "mega", "giga", "tera", "peta", "exa", "zetta", "yotta" };
  126.     char *sign = NULL;char *prefix = NULL;float pm;double factor;
  127.     int exponent10 = 0;
  128.     int use_word = 0;if(format == 5){format = 3; use_word = 1;} /* switch to using words in stead of prefix  */
  129.     if(value < 0.0) {pm = -0.5; sign = "-";value = -value;} else {sign = ""; pm = 0.5;}    
  130.     if( sig == -1 ){
  131.      /*
  132.      no significance truncations...just science notation 1234 -> 1.234*10^3
  133.      try (!) to use same amount of digits
  134.      */
  135.         sig = size;
  136.         if(format == 3){format = 1;} /* never prefix --> html notation */
  137.     }
  138.     if(value == 0){fprintf(stdout, "%s%.*f", sign, sig-1, value);return NULL;} /* no need to go further */
  139.     if(value>1){
  140.         while(value >= 10){
  141.             value=value / 10.0;
  142.             exponent10++;
  143.             /* need to set a limit to number of while loops ! */
  144.             if(exponent10 > 100){fprintf(stdout,"error : number too big (exponent > 100)\n");return 0;}
  145.         }
  146.     }
  147.     else /* 0 < value < 1 --> exponent10 < 0 */
  148.     {
  149.         while(value < 1){
  150.             value=value*10;
  151.             exponent10--;
  152.             /* need to set a limit to number of while loops ! */
  153.             if(exponent10 <-100){fprintf(stdout,"error : number too small (exponent < -100)\n");return 0;}
  154.         }
  155.     }
  156.     /* 27/9/2013 avoid truncating and do rounding...very expensive */
  157.     factor = pow(10,sig+1);
  158.     value = (round(factor*value + (pm) ))/factor; /* pm = +/- 0.5 */
  159.     if(format == 3 && ((exponent10 < PREFIX_START) || (exponent10 > PREFIX_END))){
  160.         format = 1; /* not in my list of prefixes ; print in html ! */
  161.     }
  162.     sig = sig - 1; /* "%.*f" counts the "." */
  163.     if(cnt > 1){fprintf(stdout,",");}/* more than one conversion to do : make list */
  164.     int idx=0;int exp=0;
  165.     if(exponent10 == 0){format = 6;} /* no need for 2*10^0 */
  166.     if(sig < 0){sig = 0;} /* better be safe than sorry... */
  167.     switch(format){
  168.         case 0: fprintf(stdout, "%s%.*f*10^%d", sign, sig, value, exponent10);break;
  169.         case 1: fprintf(stdout, "%s%.*f&times;10<sup>%d</sup>", sign, sig, value, exponent10);break;
  170.         case 2: fprintf(stdout, "%s%.*f \\times 10^{%d}", sign, sig, value, exponent10);break;
  171.         case 3:
  172. /*
  173. 1,1,3 -> 1
  174. 10,1,3 -> 1*10^-2 k
  175. 100,1,3 -> 1*10^-1 k
  176. 1000,1,3 -> 1 k
  177. 10000,1,3 -> 1*10^1 k
  178. 100000,1,3 -> 1*10^2 k
  179. 1000000,1,3 -> 1 M
  180. 10000000,1,3 -> 1*10^1 M
  181. 100000000,1,3 -> 1*10^2 M
  182. 1000000000,1,3 -> 1 G
  183. 1,1,3 -> 1
  184. 0.1,1,3 -> 1*10^-1
  185. 0.01,1,3 -> 1*10^-2
  186. 0.001,1,3 -> 1 m
  187. 0.0001,1,3 -> 1*10^-1 m
  188. 0.00001,1,3 -> 1*10^-2 m
  189. 0.000001,1,3 -> 1 µ
  190. 0.0000001,1,3-> 1*10^-1 µ
  191. 0.00000001,1,3-> 1*10^-2 µ
  192. 0.000000001,1,3-> 1 n
  193. */
  194.         exp = exponent10%3;
  195.         idx = round(exponent10/3);
  196.         if( exponent10 > 0  ){
  197.             if(use_word == 0 ){ prefix = plus[idx]; } else { prefix = plus_word[idx]; }
  198.         }
  199.         else
  200.         {
  201.             if(use_word == 0){ prefix = min[-1*idx]; } else { prefix = min_word[-1*idx]; }
  202.         }
  203.         if( exp == 0){
  204.             fprintf(stdout, "%s%.*f %s",sign, sig, value,prefix);
  205.         }
  206.         else
  207.         {
  208.             fprintf(stdout, "%s%.*f&times;10<sup>%d</sup> %s", sign, sig, value, exp, prefix);
  209.         }
  210.         break;
  211.         case 4: fprintf(stdout, "<math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"inline\"><mstyle id=\"wims_mathml\" mathsize=\"110%%\"><mn>%s%.*f</mn><mo>&times;</mo><msup><mn>10</mn><mn>%d</mn></msup></mstyle></math>", sign, sig, value, exponent10);break;
  212.         case 5: break;
  213.         case 6: fprintf(stdout, "%s%.*f",sign,sig,value);break;
  214.         default: break;
  215.     }
  216.     return NULL;
  217. }
  218.  
  219. int main( int argc , char *argv[]){
  220.  
  221.     if( argc < 2){
  222.         fprintf(stdout,"syntax error : number1,significance1,type1 number2,significance2,type2 ... number_n,significance_n,type_n \n");
  223.         return 0;
  224.     }
  225.  
  226.     double number = 0;
  227.     int significance = 0,type = 0,idx = 0,cnt = 1,size = 0;
  228.     char *input = "\0",*ptr = "\0";
  229.  
  230.     /* test for illegal characters */
  231.     const char *invalid_characters = "\n\"\'!=ABCDFGHIJKLMNOPQRSTUVWXYZabcdfghijklmnopqrstuvwxyz@#$%&()[]{};:~><?/\\|";
  232.     /* Ee +- are allowed : 12.34e+05  12.34e-08 */
  233.  
  234.     /* walk through argument 1 to end, and call function scienceprint(a,b,c) */
  235.     input = argv[cnt];
  236.     while( input != NULL ){
  237.         if(cnt > MAX_CONV){fprintf(stdout,"\nerror: number of conversions exceeds limit of %d\n",MAX_CONV);return 0;}
  238.         while (*input){ /* loop through invalid chars. */
  239.             if ( strchr(invalid_characters, *input) ){
  240.                 fprintf(stdout,"\nerror : illegal character \"%s\" \n",input);
  241.                 return 0;
  242.             }
  243.             input++;
  244.         }
  245.         /* reset input to actual value */
  246.         input = argv[cnt];
  247.         ptr = (char *) strtok(input,",");
  248.         idx = 0;
  249.         type = 0;
  250.         size = 0;
  251.         while( ptr != NULL ){
  252.             switch( idx ){
  253.                 case 0:
  254.                         /* size only interesting when 'significance=-1'
  255.                          determine number of digits : 1.23445e+23 -> size = 6
  256.                         */
  257.                         size = strlen(ptr);
  258.                         if( strstr(ptr,".") != NULL){size = size - 1 ;}
  259.                         if( strstr(ptr,"*10^") != NULL){
  260.                             ptr = str_replace(ptr,"*10^","E");
  261.                             if(ptr == NULL){
  262.                                 fprintf(stdout,"error : in replacement of 10^ notation\n");
  263.                                 return 0;
  264.                             }
  265.                             size = size - 3;
  266.                         }
  267.                         if( strstr(ptr,"E") != NULL){size = size - strlen(strstr(ptr,"E"));}
  268.                         if( strstr(ptr,"e") != NULL){size = size - strlen(strstr(ptr,"e"));}
  269.                         number = atof(ptr);
  270.                         break;
  271.                 case 1: significance = atoi(ptr);  break;
  272.                 case 2: type = atoi(ptr); if(type < 0 || type > 5 ){type = 0;} break;
  273.                 default: break;
  274.             }
  275.             idx++;
  276.             ptr = (char *) strtok(NULL,",");
  277.         }
  278.         /* number and precision are mandatory:  default type=0  */
  279.         if( idx < 2 || idx > 3){fprintf(stdout,"\nsyntax error : number1,significance1,type1 number2,significance2,type2 ... number_n,significance_n,type_n \n");return 0;}
  280.         /* call conversion routine */
  281.         printscience(number, significance, type , cnt , size);
  282.         cnt++;
  283.         input = argv[cnt];
  284.     }
  285.     fprintf(stdout,"\n");
  286.     return 0;
  287. }
  288.  
  289.  
  290.  
  291.