Subversion Repositories wimsdev

Rev

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

  1. /*
  2.  
  3. *********************************************************************************
  4. * J.M. Evers 3/2012                                                             *
  5. * This is all amateur scriblings... So no copyrights.                           *
  6. * This source code file, and compiled objects derived from it,                  *
  7. * can be used and distributed without restriction, including for commercial use *
  8. * No warrenty whatsoever                                                        *
  9. *********************************************************************************
  10.  
  11. 12/11/2012
  12. Added support for numbers like  12345*10^12
  13. 12345*10^12 --> 12345E12 ---> 1.2345*10^16
  14.  
  15. 18/10/2012 :
  16. Added Mathml output
  17. Added option significance=-1
  18. To be used when there is no significance known ; just tries to print the number in science notation
  19. Using the original amount of digits used in "number" argument
  20. !exec scienceprint 123.445000e+23,-1 --> 1.23445000*10^25
  21.  
  22. *********************************************************************************
  23.  
  24. WIMS usage:
  25. sci_num = !exec scienceprint number,significance,type
  26.  
  27. number: a number
  28. significance : desired precision
  29. type (optional args): calc = 0 / html = 1 / latex = 2  / prefix = 3  / mathml = 4
  30.  
  31. default  : calc   notation : 120000,3   -> 1.20*10^5
  32. type = 0 : calc   notation : 120000,3,0 -> 1.20*10^5
  33. type = 1 : html notation   : 120000,3,1 -> 1.20&times;10<sup>5</sup>
  34. type = 2 : latex notation  : 120000,3,2 -> 1.20 \times 10^{5}
  35. type = 3 : prefix-notation : 120000,3,3 -> 120.0 k
  36. type = 3 : if -24 > prefix > 24         -> type = 1 (html)
  37. type = 4 : mathml notation
  38.  
  39. multiple conversion: use space between arguments
  40. scienceprint 120000,4 122900,5 120036,6,3 --> 120.0*10^3,122.90*10^3,120.036 k
  41.  
  42. 24  yotta       Y
  43. 21  zetta       Z
  44. 18  exa         E
  45. 15  peta        P
  46. 12  tera        T
  47. 9   giga        G
  48. 6   mega        M
  49. 3   kilo        k
  50. 2   hecto       h
  51. 1   deca        da
  52. -1  deci        d
  53. -2  centi       c
  54. -3  milli       m
  55. -6  micro       µ
  56. -9  nano        n
  57. -12 pico        p
  58. -15 femto       f
  59. -18 atto        a
  60. -21 zepto       z
  61. -24 yocto       y
  62.  
  63. */
  64.  
  65. #include <stdio.h>
  66. #include <math.h>
  67. #include <string.h>
  68. #include <stdlib.h>
  69. #define MICRO "µ"
  70. #define PREFIX_START (-24)
  71. #define PREFIX_END 24
  72. #define MAX_CONV 256
  73. #define MAX_STRING 32
  74.  
  75. char *str_replace ( const char *word, const char *sub_word, const  char *rep_word ){
  76.     if(strlen(word) > MAX_STRING){return NULL;}
  77.     char *part_word = NULL;
  78.     char *new_word = NULL;
  79.     char *old_word = NULL;
  80.     char *head = NULL;
  81.     /* if either sub_word or rep_word is NULL, duplicate word a let caller handle it */
  82.     if ( sub_word == NULL || rep_word == NULL ) return strdup(word);
  83.     new_word = strdup (word);
  84.     head = new_word;
  85.     while ( (part_word = strstr ( head, sub_word ))){
  86.         old_word = new_word;
  87.         new_word = malloc ( strlen ( old_word ) - strlen ( sub_word ) + strlen ( rep_word ) + 1 );
  88.         /*failed to alloc mem, free old word and return NULL */
  89.         if ( new_word == NULL ){
  90.           free (old_word);return NULL;
  91.         }
  92.         memcpy ( new_word, old_word, part_word - old_word );
  93.         memcpy ( new_word + (part_word - old_word), rep_word, strlen ( rep_word ) );
  94.         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 ) );
  95.         memset ( new_word + strlen ( old_word ) - strlen ( sub_word ) + strlen ( rep_word ) , 0, 1 );
  96.         /* move back head right after the last replacement */
  97.         head = new_word + (part_word - old_word) + strlen( rep_word );
  98.         free (old_word);
  99.     }
  100.     return new_word;
  101. }
  102.  
  103. char *printscience(double value, int sig, int format , int cnt ,int size){
  104.     static char *prefix[] = { "y", "z", "a", "f", "p", "n", MICRO, "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" };
  105.     double display, fract;
  106.     char *sign = NULL;
  107.     int exponent10;
  108.     if( sig == -1 ){
  109.      /* no significance truncations...just science notation 1234 -> 1.234*10^3  ; try (!) to use same amount of digits*/
  110.         sig = size;
  111.         if(format == 3){format = 1;} /* no prefix --> html noation */
  112.         if(value < 0.0) {sign = "-";value = -value;sig--;} else {sign = "";}
  113.         exponent10=0;
  114.         if(value>=1){
  115.             while(value > 10){
  116.                 value=value / 10.0;
  117.                 exponent10++;
  118.                 /* need to set a limit to number of while loops ! */
  119.                 if(exponent10 > 100){fprintf(stdout,"error : number too big (exponent > 100)\n");return 0;}
  120.             }
  121.         }
  122.         else /* 0 < value < 1 --> exponent10 < 0 */
  123.         {
  124.             while(value < 1){
  125.                 value=value*10;
  126.                 exponent10--;
  127.                 /* need to set a limit to number of while loops ! */
  128.                 if(exponent10 <-100){fprintf(stdout,"error : number too small (exponent < -100)\n");return 0;}
  129.             }
  130.         }
  131.     }
  132.     else
  133.     {
  134.         if(value < 0.0) {sign = "-";value = -value;} else {sign = "";}
  135.         exponent10 = lrint( floor( log10(value) ) );/* correctly round to desired precision */
  136.         value *= pow(10.0, sig - 1 - exponent10);
  137.         fract = modf(value, &display);
  138.         if(fract >= 0.5){display += 1.0;}
  139.         value = display * pow(10.0, exponent10 - sig + 1);
  140.         if(exponent10 > 0){exponent10 = (exponent10/3)*3;}else{exponent10 = ((-exponent10+3)/3)*(-3);}
  141.         value *= pow(10.0, -exponent10);
  142.         if(format != 3){ /* allow all powers; not limited by prefix list */
  143.             if(value > 10.0){
  144.                 while(value >= 10){
  145.                     value = value / 10.0;
  146.                     exponent10++;
  147.                     /* need to set a limit to number of while loops ! */
  148.                     if(exponent10 > 100){fprintf(stdout,"error : number too big (exponent > 100)\n");return 0;}
  149.                 }
  150.             }
  151.         }
  152.         else /* steps of powers dividable by 3 used for prefix notation */
  153.         {
  154.             if (value >= 1000.0) {
  155.                 value = value / 1000.0;
  156.                 exponent10 = exponent10 + 3;
  157.             }
  158.             else
  159.             {
  160.                 if(value >= 100.0){
  161.                     sig =  sig - 2;
  162.                 }
  163.                 else
  164.                 {
  165.                     if(value >= 10.0){
  166.                         sig = sig - 1;
  167.                     }
  168.                 }
  169.             }
  170.         }
  171.     }
  172.     if(cnt > 1){fprintf(stdout,",");}
  173.     /* check on format style versus exponent */
  174.     if(exponent10 == 0 ){
  175.         format = 3; /* do not use 1.23*10^0 */
  176.     }
  177.     else
  178.     {
  179.         if(exponent10 == 1){
  180.             format = 3;/* do not use 1.23*10^1 */
  181.             value = value * 10;
  182.             sig = sig - 1;
  183.         }
  184.         else
  185.         {
  186.             if(format == 3 && ((exponent10 < PREFIX_START) || (exponent10 > PREFIX_END))){
  187.                 format = 1; /* if no prefix available, revert to html presentation */
  188.             }
  189.         }
  190.    
  191.     }
  192.     if(sig < 1){sig = 1;}
  193.     if(format != 3 ){
  194.         if( format == 0){ /* 'calculable' presentation */
  195.             fprintf(stdout, "%s%.*f*10^%d", sign, sig-1, value, exponent10);
  196.         }
  197.         else
  198.         {
  199.             if( format == 1 ){ /* html presentation */
  200.                 fprintf(stdout, "%s%.*f&times;10<sup>%d</sup>", sign, sig-1, value, exponent10);
  201.             }
  202.             else
  203.             {
  204.                 if(format == 2 ){/* latex presentation */
  205.                     fprintf(stdout, "%s%.*f \\times 10^{%d}", sign, sig-1, value, exponent10);
  206.                 }
  207.                 else
  208.                 { /* mathml presentation */
  209.                     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-1, value, exponent10);
  210.                 }
  211.             }
  212.         }
  213.     }
  214.     else /* format = 3 : prefix presentation or other more suitable presentation */
  215.     {
  216.         fprintf(stdout, "%s%.*f %s", sign, sig-1, value,prefix[(exponent10-PREFIX_START)/3]);
  217.     }
  218.     return NULL;
  219. }
  220.  
  221. int main( int argc , char *argv[]){
  222.  
  223.     if( argc < 2){
  224.         fprintf(stdout,"syntax error : number1,significance1,type1 number2,significance2,type2 ... number_n,significance_n,type_n \n");
  225.         return 0;
  226.     }
  227.  
  228.     double number = 0;
  229.     int significance = 0,type = 0,idx = 0,cnt = 1,size = 0;
  230.     char *input = "\0",*ptr = "\0";
  231.  
  232.     /* test for illegal characters */
  233.     const char *invalid_characters = "\n\"\'!=ABCDFGHIJKLMNOPQRSTUVWXYZabcdfghijklmnopqrstuvwxyz@#$%&()[]{};:~><?/\\|";
  234.     /* Ee +- are allowed : 12.34e+05  12.34e-08 */
  235.  
  236.     /* walk through argument 1 to end, and call function scienceprint(a,b,c) */
  237.     input = argv[cnt];
  238.     while( input != NULL ){
  239.         if(cnt > MAX_CONV){fprintf(stdout,"\nerror: number of conversions exceeds limit of %d\n",MAX_CONV);return 0;}
  240.         while (*input){ /* loop through invalid chars. */
  241.             if ( strchr(invalid_characters, *input) ){
  242.                 fprintf(stdout,"\nerror : illegal character \"%s\" \n",input);
  243.                 return 0;
  244.             }
  245.             input++;
  246.         }
  247.         /* reset input to actual value */
  248.         input = argv[cnt];
  249.         ptr = (char *) strtok(input,",");
  250.         idx = 0;
  251.         type = 0;
  252.         size = 0;
  253.         while( ptr != NULL ){
  254.             switch( idx ){
  255.                 case 0:
  256.                         /* size only interesting when 'significance=-1'
  257.                          determine number of digits : 1.23445e+23 -> size = 6
  258.                         */
  259.                         size = strlen(ptr);
  260.                         if( strstr(ptr,".") != NULL){size = size - 1 ;}
  261.                         if( strstr(ptr,"*10^") != NULL){
  262.                             ptr = str_replace(ptr,"*10^","E");
  263.                             if(ptr == NULL){
  264.                                 fprintf(stdout,"error : in replacement of 10^ notation\n");
  265.                                 return 0;
  266.                             }
  267.                             size = size - 3;
  268.                         }
  269.                         if( strstr(ptr,"E") != NULL){size = size - strlen(strstr(ptr,"E"));}
  270.                         if( strstr(ptr,"e") != NULL){size = size - strlen(strstr(ptr,"e"));}
  271.                         number = atof(ptr);
  272.                         break;
  273.                 case 1: significance = atoi(ptr);  break;
  274.                 case 2: type = atoi(ptr); if(type < 0 || type > 4 ){type = 0;} break;
  275.                 default: break;
  276.             }
  277.             idx++;
  278.             ptr = (char *) strtok(NULL,",");
  279.         }
  280.         /* number and precision are mandatory:  default type=0  */
  281.         if( idx < 2 || idx > 3){fprintf(stdout,"\nsyntax error : number1,significance1,type1 number2,significance2,type2 ... number_n,significance_n,type_n \n");return 0;}
  282.         /* call conversion routine */
  283.         printscience(number, significance, type , cnt , size);
  284.         cnt++;
  285.         input = argv[cnt];
  286.     }
  287.     fprintf(stdout,"\n");
  288.     return 0;
  289. }
  290.  
  291.  
  292.  
  293.