Mercurial > hg > aim92
view 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 |
line wrap: on
line source
/* op.c Ordered sequence of operations on input stream. ------ Operations on each input item are done in the order they appear on the command line. Operations can be repeated as many times as needed on the command line. Input items may be binary numbers (short or float) or ascii lines (terminated by CR) according to the type option. The list of operations is as follows. Some operations take valued arguments (which are real numbers), others are flags, as indicated: operation result for each input item x ----------------- -------------------------------------------- add=<value> x+<value> negate=on -x multiply=<value> x*<value> divide=<value> x/<value> remainder=<value> real remainder of x/<value> inverse=on 1/x round=on x rounded to nearest integer absolute=on |x| power=<value> x^<value> exponent=<value> <value>^x e-exponent=on e^x log=<value> log(x) to base <value> e-log=on log(x) to base e. sin=on sin(x) cos=on cos(x) tan=on tan(x) threshold=<value> if ( x <value> ) 0 else if ( x = <value> ) 1 diff1=on first difference diff2=on second difference diff3=on third difference cusum=on cumulative sum cumean=on cumulative (recursive) mean an cumin=on cumulative min cumax=on cumulative max The `type' option sets the data type for all input and output items. Recognised data types are: short, float, ascii. Ascii data is read in line-by-line, and comment lines are allowed. The following operation apply only to ascii input items, enabling comment lines to be stripped or echoed directly to the output. strip=<value> ignore lines beginning with <value> string echo=<value> echo lines beginning with <value> string number=on number output lines If number=on then stripped lines are not numbered; they simply dissappear. If there are no operations, (other than comment stripping/echoing or line numbering), then ascii lines are echoed. Examples: 1. To specify the following ordered sequence of operations on each binary float in the input stream: invert (take reciprocal), scale up by 100, square (raise to power 2), invert (take reciprocal), square root (raise to power 0.5). op type=float inverse=on multiply=100 power=2 inverse=on power=.5 file 2. To use as an interactive "desk calculator", eg to print out the result of log2(17/16): echo 17 | op type=ascii -div16 -log2 3. To interactively operate on a list, eg add 1 to each of the list 1,2,3, (note how to put newlines into echo'd lists): echo "1\ 2\ 3" | op type=ascii -add1 4. To read ascii data, echoing any comment lines beginning with the string "**", and for each number x in infile, o/p the number 149-x, do: op type=ascii echo="**" neg=on -add149 infile > outfile */ #include <stdio.h> #include <math.h> #include "options.h" #include "strmatch.h" char applic[] = "Ordered sequence of operations on each item in input stream.\n (Input and output in binary shorts)." ; static char *helpstr, *debugstr, *addstr , *negstr , *mulstr , *divstr , *remstr , *invstr , *rndstr , *absstr , *powstr , *expstr , *eexpstr, *logstr , *elogstr, *sinstr , *cosstr , *tanstr , *threshstr, *diff1str , *diff2str , *diff3str , *cusumstr , *cumeanstr , *cuminstr , *cumaxstr , *typestr , *stripstr , *echostr , *numstr ; static Options option[] = { { "help" , "off" , &helpstr , "help" , DEBUG }, { "debug" , "off" , &debugstr , "debugging switch" , DEBUG }, { "add" , "off" , &addstr , "Add x = x+value " , VAL }, { "negate" , "off" , &negstr , "Negate x = -x " , SETFLAG }, { "multiply" , "off" , &mulstr , "Multiply x = x*value " , VAL }, { "divide" , "off" , &divstr , "Divide x = x/value " , VAL }, { "remainder" , "off" , &remstr , "Remainder x = real remainder of x/value" , VAL }, { "inverse" , "off" , &invstr , "Inverse x = 1/x " , SETFLAG }, { "round" , "off" , &rndstr , "Round x = x, to nearest integer" , SETFLAG }, { "absolute" , "off" , &absstr , "Absolute x = |x| " , SETFLAG }, { "power" , "off" , &powstr , "Power x = x^value " , VAL }, { "exponent" , "off" , &expstr , "Exponent x = value^x " , VAL }, { "e-exponent", "off" , &eexpstr , "e-exponent x = e^x " , SETFLAG }, { "log" , "off" , &logstr , "Log x = log(x), base `value'." , VAL }, { "e-log" , "off" , &elogstr , "elog x = log(x), base e. " , SETFLAG }, { "sin" , "off" , &sinstr , "sin x = sin(x) " , SETFLAG }, { "cos" , "off" , &cosstr , "cos x = cos(x) " , SETFLAG }, { "tan" , "off" , &tanstr , "tan x = tan(x) " , SETFLAG }, { "threshold" , "off" , &threshstr , "Threshold x = 0 (x<value) or 1 (x>=value)", VAL }, { "diff1" , "off" , &diff1str , "First difference " , SETFLAG }, { "diff2" , "off" , &diff1str , "Second difference " , SETFLAG }, { "diff3" , "off" , &diff1str , "Third difference " , SETFLAG }, { "cusum" , "off" , &cusumstr , "Cumulative sum x = current sum" , SETFLAG }, { "cumean" , "off" , &cumeanstr , "Cumulative mean x = current (recursive) mean" , SETFLAG }, { "cumin" , "off" , &cuminstr , "Cumulative min x = current min " , SETFLAG }, { "cumax" , "off" , &cumaxstr , "Cumulative max x = current max " , SETFLAG }, { "type" , "short" , &typestr , "Data type (short, float, ascii)" , VAL }, { "strip" , "off" , &stripstr , "Ignore lines beginning with value string" , VAL }, { "echo" , "off" , &echostr , "Echo lines beginning with value string" , VAL }, { "number" , "off" , &numstr , "Number output lines" , SETFLAG }, ( char * ) 0 } ; #define SIZE 64 /* Max number of program command-line arguments */ #define Add 2 /* Functions */ #define Negate 3 #define Multiply 4 #define Divide 5 #define Remainder 6 #define Inverse 7 #define Round 8 #define Absolute 9 #define Power 10 #define Exp 11 #define Eexp 12 #define Log 13 #define Elog 14 #define Sin 15 #define Cos 16 #define Tan 17 #define Threshold 18 #define Diff1 19 #define Diff2 20 #define Diff3 21 #define Sum 22 #define Mean 23 #define Min 24 #define Max 25 #define Ascii 26 #define Strip 27 #define Echo 28 #define Number 29 /* data types */ #define SHORT 0 #define FLOAT 1 #define ASCII 2 int Type ; int STRIP=0; char Stripstr[]="*"; /* Default strip comment string */ int ECHO=0; char Echostr[]="**"; /* Default echo comment string */ int NUMBER=0; /* Flag for numbering ascii lines */ int n=0; /* Rounding for both +ve and -ve numbers. Real numbers are truncated to ints in the direction of zero (EG both 0.9 and -0.9 are truncated to 0). Using round, 0.9 becomes 1 and -0.9 becomes -1. (Note also 0.5 becomes 1, -0.5 becomes -1. */ #define round(x) ((x >= 0) ? ((int)(x+0.5)) : ((int)(x-0.5))) /* Remainder of real division for +ve and -ve numbers */ #define rem(x,y) ((x >= 0) ? (fabs((x) - (y)*(int)((x)/(y)))) : (fabs((x) - (y)*(int)((x)/(y)-0.5)))) /* Threshold and convert to binary (0,1) value */ #define threshold(x,T) ((x >= T) ? 1 : 0) float diff1(); float diff2(); float diff3(); float mean(); float min(); float max(); float sum(); struct opstr { /* array of operations: functions and (optional) arg */ char func; float arg; } op[SIZE]; int k=0; /* number of operations stored in array */ main(argc, argv) int argc ; char *argv[] ; { FILE *fp, *fopen(); float xf, ops(); short xs ; char s[256], stripcomment[32], echocomment[32]; char *prog, *val ; int i, index, span ; strcpy(stripcomment, Stripstr); strcpy(echocomment, Echostr ); for (i=0 ; option[i].name != (char *)0 ; i++) *(option[i].val) = option[i].dflt ; prog = argv[0] ; while ( --argc > 0 && ++argv ) { if ( ( i = whichopt( option, *argv, &index, &span ) ) == UNKNOWN ) break ; if ( ( val = checksyntax( *argv, span, option[index].type ) ) == (char *)0 ) break ; if ( i == AMBIGUOUS ) { fprintf(stderr,"%s: ambiguous option [%s]\n", prog, *argv ) ; exit ( 1 ) ; } switch ( index ) { case 0 : operate( option, index, val ) ; break; case 1 : operate( option, index, val ) ; break; case 2 : op[k].func = Add; op[k].arg = atof(val); k++; break; case 3 : op[k].func = Negate; k++; break; case 4 : op[k].func = Multiply; op[k].arg = atof(val); k++; break; case 5 : op[k].func = Divide; op[k].arg = atof(val); k++; break; case 6 : op[k].func = Remainder; op[k].arg = atof(val); k++; break; case 7 : op[k].func = Inverse; k++; break; case 8 : op[k].func = Round; k++; break; case 9 : op[k].func = Absolute; k++; break; case 10 : op[k].func = Power; op[k].arg = atof(val); k++; break; case 11 : op[k].func = Exp; op[k].arg = atof(val); k++; break; case 12 : op[k].func = Eexp; k++; break; case 13 : op[k].func = Log; op[k].arg = atof(val); k++; break; case 14 : op[k].func = Elog; k++; break; case 15 : op[k].func = Sin; k++; break; case 16 : op[k].func = Cos; k++; break; case 17 : op[k].func = Tan; k++; break; case 18 : op[k].func = Threshold; op[k].arg = atof(val); k++; break; case 19 : op[k].func = Diff1; k++; break; case 20 : op[k].func = Diff2; k++; break; case 21 : op[k].func = Diff3; k++; break; case 22 : op[k].func = Sum; k++; break; case 23 : op[k].func = Mean; k++; break; case 24 : op[k].func = Min; k++; break; case 25 : op[k].func = Max; k++; break; case 26 : Type = checktype( val ) ; break; case 27 : STRIP++; strcpy(stripcomment, val); break; case 28 : ECHO++; strcpy(echocomment, val); break; case 29 : NUMBER++; break; } } if ( !isoff( helpstr ) ) helpopts( helpstr, prog, applic, option ) ; if (argc <= 0) fp = stdin; else if ((fp = fopen(*argv, "r")) == NULL) { fprintf(stderr,"can't open %s\n", *argv); exit(1); } switch ( Type ) { case SHORT : while ( fread( &xs, sizeof(short), 1, fp ) ) { xs = (short)ops( (float)xs ) ; fwrite( &xs, sizeof(short), 1, stdout ) ; } break ; case FLOAT : while ( fread( &xf, sizeof(float), 1, fp ) ) { xf = ops( xf ) ; fwrite( &xf, sizeof(float), 1, stdout ) ; } break ; case ASCII : while (fgets(s, 256, fp)) { if (STRIP && match(s,stripcomment)==0) ; /* strip comment (ie do nothing) */ else { if (NUMBER) printf("%d: ", ++n); if (ECHO && match(s,echocomment)==0) fputs(s,stdout); /* echo comment */ else { if ( k>0 ) { xf = ops( atof(s) ) ; printf("%.3f\n", xf ) ; } else fputs(s,stdout); /* echo line (case of no ops) */ } } } break ; } fclose(fp); } checktype( s ) char *s ; { if ( iststr( s, "short" ) ) return SHORT ; if ( iststr( s, "float" ) ) return FLOAT ; if ( iststr( s, "ascii" ) ) return ASCII ; fprintf( stderr,"unknown datatype [%s]\n", s ) ; exit( 1 ) ; } float ops(x) float x; { int i; for (i=0 ; i<k ; i++) switch (op[i].func) { case Add: x = x+op[i].arg; break; case Negate: x = (-x); break; case Multiply: x = x*op[i].arg; break; case Divide: x = x/op[i].arg; break; case Remainder: x = rem(x,op[i].arg); break; case Inverse: x = 1.0/x; break; case Round: x = round(x); break; case Absolute: x = fabs(x); break; case Power: x = pow(x,op[i].arg); break; case Exp: x = pow(op[i].arg,x); break; case Eexp: x = exp(x); break; case Log: x = log(x)/log(op[i].arg); break; case Elog: x = log(x); break; case Sin: x = sin(x); break; case Cos: x = cos(x); break; case Tan: x = tan(x); break; case Threshold: x = threshold(x,op[i].arg); break; case Diff1: x = diff1(x); break; case Diff2: x = diff2(x); break; case Diff3: x = diff3(x); break; case Sum: x = sum(x); break; case Mean: x = mean(x); break; case Min: x = min(x); break; case Max: x = max(x); break; } return x; } match(s1,s2) char *s1, *s2; { int n1, n2; if ((n1=strlen(s1)) < (n2=strlen(s2))) return strncmp(s1,s2,n1); else return strncmp(s1,s2,n2); } /**************************************************************************** The past values used to compute differences are, (in the order they would appear in an array, where x is the current value): 1st diffs ... x11 x 2nd diffs ... x22 x21 x 3rd diffs ... x33 x32 x31 x *****************************************************************************/ float diff1(x) float x; { static float x11=0; float d; d=fabs(x11-x); x11=x; return d; } float diff2(x) float x; { static float x21=0, x22=0; float d; d=fabs( fabs(x22-x21)-fabs(x21-x) ); x22=x21; x21=x; return d; } float diff3(x) float x; { static float x31=0, x32=0, x33=0; float d; d=fabs( fabs( fabs(x33-x32)-fabs(x32-x31) ) - fabs( fabs(x32-x31)-fabs(x31-x) ) ); x33=x32; x32=x31; x31=x; return d; } /**************************************************************************** Recurisve estimation of the mean (Ref: Young, eqn 2.14 (p14), eqn VI(2) (p63), eqn 5.17 (p65)) ****************************************************************************/ float mean(x) float x; { static float a = 0; /* initial mean value */ static float p = 10000; /* initial gain factor [Young p65] */ p = p/(1+p); /* update p (the gain factor) */ a = a - p*(a-x); /* update a (the mean estimate) */ return a; } /**************************************************************************** Min, Max, and Sum ****************************************************************************/ float min(x) float x; { static float MIN=1.0e30; if (x < MIN) MIN = x; return MIN; } float max(x) float x; { static float MAX=0; if (x > MAX) MAX = x; return MAX; } float sum(x) float x; { static float SUM=0; SUM += x; return SUM; }