Mercurial > hg > aim92
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/op.c Fri May 20 15:19:45 2011 +0100 @@ -0,0 +1,492 @@ +/* + 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; +}