Mercurial > hg > aim92
comparison tools/op.c @ 0:5242703e91d3 tip
Initial checkin for AIM92 aimR8.2 (last updated May 1997).
author | tomwalters |
---|---|
date | Fri, 20 May 2011 15:19:45 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:5242703e91d3 |
---|---|
1 /* | |
2 op.c Ordered sequence of operations on input stream. | |
3 ------ | |
4 | |
5 Operations on each input item are done in the order they appear on the | |
6 command line. Operations can be repeated as many times as needed on the | |
7 command line. | |
8 | |
9 Input items may be binary numbers (short or float) or ascii lines | |
10 (terminated by CR) according to the type option. | |
11 | |
12 The list of operations is as follows. Some operations take valued | |
13 arguments (which are real numbers), others are flags, as indicated: | |
14 | |
15 operation result for each input item x | |
16 ----------------- -------------------------------------------- | |
17 add=<value> x+<value> | |
18 negate=on -x | |
19 multiply=<value> x*<value> | |
20 divide=<value> x/<value> | |
21 remainder=<value> real remainder of x/<value> | |
22 inverse=on 1/x | |
23 round=on x rounded to nearest integer | |
24 absolute=on |x| | |
25 power=<value> x^<value> | |
26 exponent=<value> <value>^x | |
27 e-exponent=on e^x | |
28 log=<value> log(x) to base <value> | |
29 e-log=on log(x) to base e. | |
30 sin=on sin(x) | |
31 cos=on cos(x) | |
32 tan=on tan(x) | |
33 threshold=<value> if ( x <value> ) 0 else if ( x = <value> ) 1 | |
34 diff1=on first difference | |
35 diff2=on second difference | |
36 diff3=on third difference | |
37 cusum=on cumulative sum | |
38 cumean=on cumulative (recursive) mean an | |
39 cumin=on cumulative min | |
40 cumax=on cumulative max | |
41 | |
42 The `type' option sets the data type for all input and output items. | |
43 Recognised data types are: short, float, ascii. | |
44 | |
45 | |
46 Ascii data is read in line-by-line, and comment lines are allowed. | |
47 The following operation apply only to ascii input items, enabling | |
48 comment lines to be stripped or echoed directly to the output. | |
49 | |
50 strip=<value> ignore lines beginning with <value> string | |
51 echo=<value> echo lines beginning with <value> string | |
52 number=on number output lines | |
53 If number=on then stripped lines are | |
54 not numbered; they simply dissappear. | |
55 | |
56 If there are no operations, (other than comment stripping/echoing or line | |
57 numbering), then ascii lines are echoed. | |
58 | |
59 | |
60 Examples: | |
61 | |
62 1. To specify the following ordered sequence of operations on each binary | |
63 float in the input stream: invert (take reciprocal), scale up by 100, | |
64 square (raise to power 2), invert (take reciprocal), square root (raise to | |
65 power 0.5). | |
66 | |
67 op type=float inverse=on multiply=100 power=2 inverse=on power=.5 file | |
68 | |
69 | |
70 2. To use as an interactive "desk calculator", eg to print out the result | |
71 of log2(17/16): | |
72 | |
73 echo 17 | op type=ascii -div16 -log2 | |
74 | |
75 3. To interactively operate on a list, eg add 1 to each of the list 1,2,3, | |
76 (note how to put newlines into echo'd lists): | |
77 | |
78 echo "1\ | |
79 2\ | |
80 3" | op type=ascii -add1 | |
81 | |
82 4. To read ascii data, echoing any comment lines beginning with the string | |
83 "**", and for each number x in infile, o/p the number 149-x, do: | |
84 | |
85 op type=ascii echo="**" neg=on -add149 infile > outfile | |
86 | |
87 */ | |
88 | |
89 #include <stdio.h> | |
90 #include <math.h> | |
91 #include "options.h" | |
92 #include "strmatch.h" | |
93 | |
94 char applic[] = "Ordered sequence of operations on each item in input stream.\n (Input and output in binary shorts)." ; | |
95 | |
96 static char *helpstr, *debugstr, | |
97 *addstr , | |
98 *negstr , | |
99 *mulstr , | |
100 *divstr , | |
101 *remstr , | |
102 *invstr , | |
103 *rndstr , | |
104 *absstr , | |
105 *powstr , | |
106 *expstr , | |
107 *eexpstr, | |
108 *logstr , | |
109 *elogstr, | |
110 *sinstr , | |
111 *cosstr , | |
112 *tanstr , | |
113 *threshstr, | |
114 *diff1str , | |
115 *diff2str , | |
116 *diff3str , | |
117 *cusumstr , | |
118 *cumeanstr , | |
119 *cuminstr , | |
120 *cumaxstr , | |
121 *typestr , | |
122 *stripstr , | |
123 *echostr , | |
124 *numstr ; | |
125 | |
126 static Options option[] = { | |
127 { "help" , "off" , &helpstr , "help" , DEBUG }, | |
128 { "debug" , "off" , &debugstr , "debugging switch" , DEBUG }, | |
129 { "add" , "off" , &addstr , "Add x = x+value " , VAL }, | |
130 { "negate" , "off" , &negstr , "Negate x = -x " , SETFLAG }, | |
131 { "multiply" , "off" , &mulstr , "Multiply x = x*value " , VAL }, | |
132 { "divide" , "off" , &divstr , "Divide x = x/value " , VAL }, | |
133 { "remainder" , "off" , &remstr , "Remainder x = real remainder of x/value" , VAL }, | |
134 { "inverse" , "off" , &invstr , "Inverse x = 1/x " , SETFLAG }, | |
135 { "round" , "off" , &rndstr , "Round x = x, to nearest integer" , SETFLAG }, | |
136 { "absolute" , "off" , &absstr , "Absolute x = |x| " , SETFLAG }, | |
137 { "power" , "off" , &powstr , "Power x = x^value " , VAL }, | |
138 { "exponent" , "off" , &expstr , "Exponent x = value^x " , VAL }, | |
139 { "e-exponent", "off" , &eexpstr , "e-exponent x = e^x " , SETFLAG }, | |
140 { "log" , "off" , &logstr , "Log x = log(x), base `value'." , VAL }, | |
141 { "e-log" , "off" , &elogstr , "elog x = log(x), base e. " , SETFLAG }, | |
142 { "sin" , "off" , &sinstr , "sin x = sin(x) " , SETFLAG }, | |
143 { "cos" , "off" , &cosstr , "cos x = cos(x) " , SETFLAG }, | |
144 { "tan" , "off" , &tanstr , "tan x = tan(x) " , SETFLAG }, | |
145 { "threshold" , "off" , &threshstr , "Threshold x = 0 (x<value) or 1 (x>=value)", VAL }, | |
146 { "diff1" , "off" , &diff1str , "First difference " , SETFLAG }, | |
147 { "diff2" , "off" , &diff1str , "Second difference " , SETFLAG }, | |
148 { "diff3" , "off" , &diff1str , "Third difference " , SETFLAG }, | |
149 { "cusum" , "off" , &cusumstr , "Cumulative sum x = current sum" , SETFLAG }, | |
150 { "cumean" , "off" , &cumeanstr , "Cumulative mean x = current (recursive) mean" , SETFLAG }, | |
151 { "cumin" , "off" , &cuminstr , "Cumulative min x = current min " , SETFLAG }, | |
152 { "cumax" , "off" , &cumaxstr , "Cumulative max x = current max " , SETFLAG }, | |
153 { "type" , "short" , &typestr , "Data type (short, float, ascii)" , VAL }, | |
154 { "strip" , "off" , &stripstr , "Ignore lines beginning with value string" , VAL }, | |
155 { "echo" , "off" , &echostr , "Echo lines beginning with value string" , VAL }, | |
156 { "number" , "off" , &numstr , "Number output lines" , SETFLAG }, | |
157 ( char * ) 0 } ; | |
158 | |
159 | |
160 #define SIZE 64 /* Max number of program command-line arguments */ | |
161 | |
162 #define Add 2 /* Functions */ | |
163 #define Negate 3 | |
164 #define Multiply 4 | |
165 #define Divide 5 | |
166 #define Remainder 6 | |
167 #define Inverse 7 | |
168 #define Round 8 | |
169 #define Absolute 9 | |
170 #define Power 10 | |
171 #define Exp 11 | |
172 #define Eexp 12 | |
173 #define Log 13 | |
174 #define Elog 14 | |
175 #define Sin 15 | |
176 #define Cos 16 | |
177 #define Tan 17 | |
178 #define Threshold 18 | |
179 #define Diff1 19 | |
180 #define Diff2 20 | |
181 #define Diff3 21 | |
182 #define Sum 22 | |
183 #define Mean 23 | |
184 #define Min 24 | |
185 #define Max 25 | |
186 #define Ascii 26 | |
187 #define Strip 27 | |
188 #define Echo 28 | |
189 #define Number 29 | |
190 | |
191 | |
192 /* data types */ | |
193 | |
194 #define SHORT 0 | |
195 #define FLOAT 1 | |
196 #define ASCII 2 | |
197 | |
198 int Type ; | |
199 | |
200 int STRIP=0; | |
201 char Stripstr[]="*"; /* Default strip comment string */ | |
202 | |
203 int ECHO=0; | |
204 char Echostr[]="**"; /* Default echo comment string */ | |
205 | |
206 int NUMBER=0; /* Flag for numbering ascii lines */ | |
207 int n=0; | |
208 | |
209 /* | |
210 Rounding for both +ve and -ve numbers. Real numbers are truncated to ints in | |
211 the direction of zero (EG both 0.9 and -0.9 are truncated to 0). Using round, | |
212 0.9 becomes 1 and -0.9 becomes -1. (Note also 0.5 becomes 1, -0.5 becomes -1. | |
213 */ | |
214 #define round(x) ((x >= 0) ? ((int)(x+0.5)) : ((int)(x-0.5))) | |
215 | |
216 /* Remainder of real division for +ve and -ve numbers */ | |
217 #define rem(x,y) ((x >= 0) ? (fabs((x) - (y)*(int)((x)/(y)))) : (fabs((x) - (y)*(int)((x)/(y)-0.5)))) | |
218 | |
219 /* Threshold and convert to binary (0,1) value */ | |
220 #define threshold(x,T) ((x >= T) ? 1 : 0) | |
221 | |
222 float diff1(); | |
223 float diff2(); | |
224 float diff3(); | |
225 float mean(); | |
226 float min(); | |
227 float max(); | |
228 float sum(); | |
229 | |
230 struct opstr { /* array of operations: functions and (optional) arg */ | |
231 char func; | |
232 float arg; | |
233 } op[SIZE]; | |
234 | |
235 int k=0; /* number of operations stored in array */ | |
236 | |
237 main(argc, argv) | |
238 int argc ; | |
239 char *argv[] ; | |
240 { | |
241 FILE *fp, *fopen(); | |
242 float xf, ops(); | |
243 short xs ; | |
244 char s[256], stripcomment[32], echocomment[32]; | |
245 char *prog, *val ; | |
246 int i, index, span ; | |
247 | |
248 strcpy(stripcomment, Stripstr); | |
249 strcpy(echocomment, Echostr ); | |
250 | |
251 for (i=0 ; option[i].name != (char *)0 ; i++) | |
252 *(option[i].val) = option[i].dflt ; | |
253 | |
254 prog = argv[0] ; | |
255 while ( --argc > 0 && ++argv ) { | |
256 if ( ( i = whichopt( option, *argv, &index, &span ) ) == UNKNOWN ) | |
257 break ; | |
258 if ( ( val = checksyntax( *argv, span, option[index].type ) ) == (char *)0 ) | |
259 break ; | |
260 if ( i == AMBIGUOUS ) { | |
261 fprintf(stderr,"%s: ambiguous option [%s]\n", prog, *argv ) ; | |
262 exit ( 1 ) ; | |
263 } | |
264 switch ( index ) { | |
265 case 0 : operate( option, index, val ) ; break; | |
266 case 1 : operate( option, index, val ) ; break; | |
267 case 2 : op[k].func = Add; op[k].arg = atof(val); k++; break; | |
268 case 3 : op[k].func = Negate; k++; break; | |
269 case 4 : op[k].func = Multiply; op[k].arg = atof(val); k++; break; | |
270 case 5 : op[k].func = Divide; op[k].arg = atof(val); k++; break; | |
271 case 6 : op[k].func = Remainder; op[k].arg = atof(val); k++; break; | |
272 case 7 : op[k].func = Inverse; k++; break; | |
273 case 8 : op[k].func = Round; k++; break; | |
274 case 9 : op[k].func = Absolute; k++; break; | |
275 case 10 : op[k].func = Power; op[k].arg = atof(val); k++; break; | |
276 case 11 : op[k].func = Exp; op[k].arg = atof(val); k++; break; | |
277 case 12 : op[k].func = Eexp; k++; break; | |
278 case 13 : op[k].func = Log; op[k].arg = atof(val); k++; break; | |
279 case 14 : op[k].func = Elog; k++; break; | |
280 case 15 : op[k].func = Sin; k++; break; | |
281 case 16 : op[k].func = Cos; k++; break; | |
282 case 17 : op[k].func = Tan; k++; break; | |
283 case 18 : op[k].func = Threshold; op[k].arg = atof(val); k++; break; | |
284 case 19 : op[k].func = Diff1; k++; break; | |
285 case 20 : op[k].func = Diff2; k++; break; | |
286 case 21 : op[k].func = Diff3; k++; break; | |
287 case 22 : op[k].func = Sum; k++; break; | |
288 case 23 : op[k].func = Mean; k++; break; | |
289 case 24 : op[k].func = Min; k++; break; | |
290 case 25 : op[k].func = Max; k++; break; | |
291 case 26 : Type = checktype( val ) ; break; | |
292 case 27 : STRIP++; strcpy(stripcomment, val); break; | |
293 case 28 : ECHO++; strcpy(echocomment, val); break; | |
294 case 29 : NUMBER++; break; | |
295 } | |
296 | |
297 } | |
298 if ( !isoff( helpstr ) ) | |
299 helpopts( helpstr, prog, applic, option ) ; | |
300 | |
301 if (argc <= 0) fp = stdin; | |
302 else if ((fp = fopen(*argv, "r")) == NULL) { | |
303 fprintf(stderr,"can't open %s\n", *argv); | |
304 exit(1); | |
305 } | |
306 | |
307 switch ( Type ) { | |
308 | |
309 case SHORT : | |
310 while ( fread( &xs, sizeof(short), 1, fp ) ) { | |
311 xs = (short)ops( (float)xs ) ; | |
312 fwrite( &xs, sizeof(short), 1, stdout ) ; | |
313 } | |
314 break ; | |
315 | |
316 case FLOAT : | |
317 while ( fread( &xf, sizeof(float), 1, fp ) ) { | |
318 xf = ops( xf ) ; | |
319 fwrite( &xf, sizeof(float), 1, stdout ) ; | |
320 } | |
321 break ; | |
322 | |
323 case ASCII : | |
324 while (fgets(s, 256, fp)) { | |
325 if (STRIP && match(s,stripcomment)==0) | |
326 ; /* strip comment (ie do nothing) */ | |
327 else { | |
328 if (NUMBER) printf("%d: ", ++n); | |
329 if (ECHO && match(s,echocomment)==0) | |
330 fputs(s,stdout); /* echo comment */ | |
331 else { | |
332 if ( k>0 ) { | |
333 xf = ops( atof(s) ) ; | |
334 printf("%.3f\n", xf ) ; | |
335 } | |
336 else fputs(s,stdout); /* echo line (case of no ops) */ | |
337 } | |
338 } | |
339 } | |
340 break ; | |
341 } | |
342 | |
343 fclose(fp); | |
344 } | |
345 | |
346 | |
347 checktype( s ) | |
348 char *s ; | |
349 { | |
350 if ( iststr( s, "short" ) ) return SHORT ; | |
351 if ( iststr( s, "float" ) ) return FLOAT ; | |
352 if ( iststr( s, "ascii" ) ) return ASCII ; | |
353 fprintf( stderr,"unknown datatype [%s]\n", s ) ; | |
354 exit( 1 ) ; | |
355 } | |
356 | |
357 | |
358 float ops(x) | |
359 float x; | |
360 { | |
361 int i; | |
362 | |
363 for (i=0 ; i<k ; i++) | |
364 switch (op[i].func) { | |
365 case Add: x = x+op[i].arg; break; | |
366 case Negate: x = (-x); break; | |
367 case Multiply: x = x*op[i].arg; break; | |
368 case Divide: x = x/op[i].arg; break; | |
369 case Remainder: x = rem(x,op[i].arg); break; | |
370 case Inverse: x = 1.0/x; break; | |
371 case Round: x = round(x); break; | |
372 case Absolute: x = fabs(x); break; | |
373 case Power: x = pow(x,op[i].arg); break; | |
374 case Exp: x = pow(op[i].arg,x); break; | |
375 case Eexp: x = exp(x); break; | |
376 case Log: x = log(x)/log(op[i].arg); break; | |
377 case Elog: x = log(x); break; | |
378 case Sin: x = sin(x); break; | |
379 case Cos: x = cos(x); break; | |
380 case Tan: x = tan(x); break; | |
381 case Threshold: x = threshold(x,op[i].arg); break; | |
382 case Diff1: x = diff1(x); break; | |
383 case Diff2: x = diff2(x); break; | |
384 case Diff3: x = diff3(x); break; | |
385 case Sum: x = sum(x); break; | |
386 case Mean: x = mean(x); break; | |
387 case Min: x = min(x); break; | |
388 case Max: x = max(x); break; | |
389 } | |
390 return x; | |
391 } | |
392 | |
393 | |
394 match(s1,s2) | |
395 char *s1, *s2; | |
396 { | |
397 int n1, n2; | |
398 | |
399 if ((n1=strlen(s1)) < (n2=strlen(s2))) | |
400 return strncmp(s1,s2,n1); | |
401 else | |
402 return strncmp(s1,s2,n2); | |
403 } | |
404 | |
405 | |
406 /**************************************************************************** | |
407 The past values used to compute differences are, (in the order they would | |
408 appear in an array, where x is the current value): | |
409 1st diffs ... x11 x | |
410 2nd diffs ... x22 x21 x | |
411 3rd diffs ... x33 x32 x31 x | |
412 *****************************************************************************/ | |
413 float diff1(x) | |
414 float x; | |
415 { | |
416 static float x11=0; | |
417 float d; | |
418 | |
419 d=fabs(x11-x); | |
420 x11=x; | |
421 return d; | |
422 } | |
423 | |
424 float diff2(x) | |
425 float x; | |
426 { | |
427 static float x21=0, x22=0; | |
428 float d; | |
429 | |
430 d=fabs( fabs(x22-x21)-fabs(x21-x) ); | |
431 x22=x21; | |
432 x21=x; | |
433 return d; | |
434 } | |
435 | |
436 float diff3(x) | |
437 float x; | |
438 { | |
439 static float x31=0, x32=0, x33=0; | |
440 float d; | |
441 | |
442 d=fabs( fabs( fabs(x33-x32)-fabs(x32-x31) ) - fabs( fabs(x32-x31)-fabs(x31-x) ) ); | |
443 x33=x32; | |
444 x32=x31; | |
445 x31=x; | |
446 return d; | |
447 } | |
448 | |
449 /**************************************************************************** | |
450 Recurisve estimation of the mean | |
451 (Ref: Young, eqn 2.14 (p14), eqn VI(2) (p63), eqn 5.17 (p65)) | |
452 ****************************************************************************/ | |
453 float mean(x) | |
454 float x; | |
455 { | |
456 static float a = 0; /* initial mean value */ | |
457 static float p = 10000; /* initial gain factor [Young p65] */ | |
458 | |
459 p = p/(1+p); /* update p (the gain factor) */ | |
460 a = a - p*(a-x); /* update a (the mean estimate) */ | |
461 return a; | |
462 } | |
463 | |
464 /**************************************************************************** | |
465 Min, Max, and Sum | |
466 ****************************************************************************/ | |
467 float min(x) | |
468 float x; | |
469 { | |
470 static float MIN=1.0e30; | |
471 | |
472 if (x < MIN) MIN = x; | |
473 return MIN; | |
474 } | |
475 | |
476 float max(x) | |
477 float x; | |
478 { | |
479 static float MAX=0; | |
480 | |
481 if (x > MAX) MAX = x; | |
482 return MAX; | |
483 } | |
484 | |
485 float sum(x) | |
486 float x; | |
487 { | |
488 static float SUM=0; | |
489 | |
490 SUM += x; | |
491 return SUM; | |
492 } |