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 }