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