numtools

perform numerical operations on vectors and matrices in unix pipes
git clone git://src.adamsgaard.dk/numtools # fast
git clone https://src.adamsgaard.dk/numtools.git # slow
Log | Files | Refs | README | LICENSE Back to index

commit 8b5e9b0cf97126537c548e49329ead6bad47c105
parent 5c71d867b926ca74ab063744b0359086be572e88
Author: Anders Damsgaard <anders@adamsgaard.dk>
Date:   Mon,  9 May 2022 16:52:46 +0200

add option parsing and format string options to all programs

Diffstat:
Mmax.1 | 17++++++++++++++++-
Mmax.c | 32+++++++++++++++++++++++++++++---
Mmean.1 | 16++++++++++++++++
Mmean.c | 32+++++++++++++++++++++++++++++---
Mmin.1 | 16++++++++++++++++
Mmin.c | 32+++++++++++++++++++++++++++++---
Mstddev.1 | 9+++++++++
Mstddev.c | 24++++++++++++++++--------
Mstdvar.1 | 9+++++++++
Mstdvar.c | 12++++++++++--
Msum.1 | 16++++++++++++++++
Msum.c | 32+++++++++++++++++++++++++++++---
Mutil.c | 13+++++++++++++
Mutil.h | 1+
14 files changed, 238 insertions(+), 23 deletions(-)

diff --git a/max.1 b/max.1 @@ -6,13 +6,28 @@ .Nd returns the maximum value for each column .Sh SYNOPSIS .Nm -.Op Ar file +.Op Fl f Ar fmtstr +.Op Fl h .Sh DESCRIPTION .Nm returns the maximum numerical value for each column in standard input. Input fields must be tab-separated and each line must contain the same number of fields. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl f Ar fmtstr +Formatting string to use as documented in +.Xr printf 3 . +When including a format specifier (%..), only use forms that are +compatible with +.Vt double +types. +The default format string is '%.17g'. +.It Fl h +Show usage information and exit. +.El .Sh EXAMPLES .Dl $ printf '1\et2\et3\en4\et5\et6\en' | max .Dl 4 5 6 diff --git a/max.c b/max.c @@ -2,19 +2,45 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <limits.h> +#include "arg.h" #include "util.h" +char *argv0; + +static void +usage(void) +{ + errx(1, "usage: %s [-f fmtstr] [-h] ", argv0); +} + int -main(void) +main(int argc, char *argv[]) { + int ret; size_t i = 0, nf = 0, nr = 0, linesize = 0; - char *line = NULL, *data = NULL; + char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g"; double val, *vals = NULL; if (pledge("stdio", NULL) == -1) err(2, "pledge"); + ARGBEGIN { + case 'f': + ret = snprintf(fmtstr, sizeof(fmtstr), "%s", EARGF(usage())); + if (ret < 0 || (size_t)ret >= sizeof(fmtstr)) + errx(1, "%s: could not write fmtstr", __func__); + break; + case 'h': + usage(); + break; + default: + usage(); + } ARGEND; + if (argc > 0) + usage(); + while (getline(&line, &linesize, stdin) > 0) { if (nr == 0) if ((nf = allocarr(&vals, line, linesize)) == 0) @@ -28,7 +54,7 @@ main(void) } nr++; } - printarr(vals, nf); + printfarr(fmtstr, vals, nf); free(line); free(vals); diff --git a/mean.1 b/mean.1 @@ -6,11 +6,27 @@ .Nd returns the average value for each column .Sh SYNOPSIS .Nm +.Op Fl f Ar fmtstr +.Op Fl h .Sh DESCRIPTION .Nm returns the mean numerical value for each column in standard input. Input fields must be tab-separated and each line must contain the same number of fields. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl f Ar fmtstr +Formatting string to use as documented in +.Xr printf 3 . +When including a format specifier (%..), only use forms that are +compatible with +.Vt double +types. +The default format string is '%.17g'. +.It Fl h +Show usage information and exit. +.El .Sh EXAMPLES .Dl $ printf '1\et2\et3\en4\et5\et6\en' | mean .Dl 2.5 3.5 4.5 diff --git a/mean.c b/mean.c @@ -2,19 +2,45 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <limits.h> +#include "arg.h" #include "util.h" +char *argv0; + +static void +usage(void) +{ + errx(1, "usage: %s [-f fmtstr] [-h] ", argv0); +} + int -main(void) +main(int argc, char *argv[]) { + int ret; size_t i = 0, nf = 0, nr = 0, linesize = 0; - char *line = NULL, *data = NULL; + char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g"; double val, *vals = NULL; if (pledge("stdio", NULL) == -1) err(2, "pledge"); + ARGBEGIN { + case 'f': + ret = snprintf(fmtstr, sizeof(fmtstr), "%s", EARGF(usage())); + if (ret < 0 || (size_t)ret >= sizeof(fmtstr)) + errx(1, "%s: could not write fmtstr", __func__); + break; + case 'h': + usage(); + break; + default: + usage(); + } ARGEND; + if (argc > 0) + usage(); + while (getline(&line, &linesize, stdin) > 0) { if (nr == 0) if ((nf = allocarr(&vals, line, linesize)) == 0) @@ -31,7 +57,7 @@ main(void) } for (i = 0; i < nf; i++) vals[i] /= (double)nr; - printarr(vals, nf); + printfarr(fmtstr, vals, nf); free(line); free(vals); diff --git a/min.1 b/min.1 @@ -6,12 +6,28 @@ .Nd returns the minimum value for each column .Sh SYNOPSIS .Nm +.Op Fl f Ar fmtstr +.Op Fl h .Sh DESCRIPTION .Nm returns the minimum numerical value for each column in standard input. Input fields must be tab-separated and each line must contain the same number of fields. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl f Ar fmtstr +Formatting string to use as documented in +.Xr printf 3 . +When including a format specifier (%..), only use forms that are +compatible with +.Vt double +types. +The default format string is '%.17g'. +.It Fl h +Show usage information and exit. +.El .Sh EXAMPLES .Dl $ printf '1\et2\et3\en4\et5\et6\en' | min .Dl 1 2 3 diff --git a/min.c b/min.c @@ -2,19 +2,45 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <limits.h> +#include "arg.h" #include "util.h" +char *argv0; + +static void +usage(void) +{ + errx(1, "usage: %s [-f fmtstr] [-h] ", argv0); +} + int -main(void) +main(int argc, char *argv[]) { + int ret; size_t i = 0, nf = 0, nr = 0, linesize = 0; - char *line = NULL, *data = NULL; + char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g"; double val, *vals = NULL; if (pledge("stdio", NULL) == -1) err(2, "pledge"); + ARGBEGIN { + case 'f': + ret = snprintf(fmtstr, sizeof(fmtstr), "%s", EARGF(usage())); + if (ret < 0 || (size_t)ret >= sizeof(fmtstr)) + errx(1, "%s: could not write fmtstr", __func__); + break; + case 'h': + usage(); + break; + default: + usage(); + } ARGEND; + if (argc > 0) + usage(); + while (getline(&line, &linesize, stdin) > 0) { if (nr == 0) if ((nf = allocarr(&vals, line, linesize)) == 0) @@ -28,7 +54,7 @@ main(void) } nr++; } - printarr(vals, nf); + printfarr(fmtstr, vals, nf); free(line); free(vals); diff --git a/stddev.1 b/stddev.1 @@ -6,6 +6,7 @@ .Nd returns the standard deviation for each column .Sh SYNOPSIS .Nm +.Op Fl f Ar fmtstr .Op Fl h .Op Fl u .Sh DESCRIPTION @@ -18,6 +19,14 @@ The output is always in full double precision. .Pp The options are as follows: .Bl -tag -width Ds +.It Fl f Ar fmtstr +Formatting string to use as documented in +.Xr printf 3 . +When including a format specifier (%..), only use forms that are +compatible with +.Vt double +types. +The default format string is '%.17g'. .It Fl h Show usage information and exit. .It Fl u diff --git a/stddev.c b/stddev.c @@ -3,6 +3,7 @@ #include <stdlib.h> #include <unistd.h> #include <math.h> +#include <limits.h> #include "arg.h" #include "util.h" @@ -12,19 +13,26 @@ char *argv0; static void usage(void) { - errx(1, "usage: %s [-h] [-u]\n", argv0); + errx(1, "usage: %s [-f fmtstr] [-h] [-u]\n", argv0); } int main(int argc, char *argv[]) { + int ret; size_t i, j, nf = 0, nr = 0, correction = 1; - double *means = NULL, *stdvars = NULL, **vals = NULL; + double *means = NULL, *stdvals = NULL, **vals = NULL; + char fmtstr[PATH_MAX] = "%.17g"; if (pledge("stdio", NULL) == -1) err(2, "pledge"); ARGBEGIN { + case 'f': + ret = snprintf(fmtstr, sizeof(fmtstr), "%s", EARGF(usage())); + if (ret < 0 || (size_t)ret >= sizeof(fmtstr)) + errx(1, "%s: could not write fmtstr", __func__); + break; case 'h': usage(); break; @@ -38,7 +46,7 @@ main(int argc, char *argv[]) nr = fscanmatrix(stdin, &vals, &nf); if (!(means = calloc(nf, sizeof(double))) || - !(stdvars = calloc(nf, sizeof(double)))) + !(stdvals = calloc(nf, sizeof(double)))) err(1, "calloc"); for (i = 0; i < nf; i++) { @@ -49,16 +57,16 @@ main(int argc, char *argv[]) } for (i = 0; i < nf; i++) { - stdvars[i] = 0.0; + stdvals[i] = 0.0; for (j = 0; j < nr; j++) - stdvars[i] += pow(vals[j][i] - means[i], 2.0); - stdvars[i] = sqrt(stdvars[i] / ((double)(nr - correction))); + stdvals[i] += pow(vals[j][i] - means[i], 2.0); + stdvals[i] = sqrt(stdvals[i] / ((double)(nr - correction))); } - printarr(stdvars, nf); + printfarr(fmtstr, stdvals, nf); free(means); - free(stdvars); + free(stdvals); for (i = 0; i < nr; i++) free(vals[i]); free(vals); diff --git a/stdvar.1 b/stdvar.1 @@ -6,6 +6,7 @@ .Nd returns the standard variance for each column .Sh SYNOPSIS .Nm +.Op Fl f Ar fmtstr .Op Fl h .Op Fl u .Sh DESCRIPTION @@ -18,6 +19,14 @@ The output is always in full double precision. .Pp The options are as follows: .Bl -tag -width Ds +.It Fl f Ar fmtstr +Formatting string to use as documented in +.Xr printf 3 . +When including a format specifier (%..), only use forms that are +compatible with +.Vt double +types. +The default format string is '%.17g'. .It Fl h Show usage information and exit. .It Fl u diff --git a/stdvar.c b/stdvar.c @@ -3,6 +3,7 @@ #include <stdlib.h> #include <unistd.h> #include <math.h> +#include <limits.h> #include "arg.h" #include "util.h" @@ -12,19 +13,26 @@ char *argv0; static void usage(void) { - errx(1, "usage: %s [-h] [-u]\n", argv0); + errx(1, "usage: %s [-f fmtstr] [-h] [-u]\n", argv0); } int main(int argc, char *argv[]) { + int ret; size_t i, j, nf = 0, nr = 0, correction = 1; double *means = NULL, *stdvars = NULL, **vals = NULL; + char fmtstr[PATH_MAX] = "%.17g"; if (pledge("stdio", NULL) == -1) err(2, "pledge"); ARGBEGIN { + case 'f': + ret = snprintf(fmtstr, sizeof(fmtstr), "%s", EARGF(usage())); + if (ret < 0 || (size_t)ret >= sizeof(fmtstr)) + errx(1, "%s: could not write fmtstr", __func__); + break; case 'h': usage(); break; @@ -55,7 +63,7 @@ main(int argc, char *argv[]) stdvars[i] /= (double)(nr - correction); } - printarr(stdvars, nf); + printfarr(fmtstr, stdvars, nf); free(means); free(stdvars); diff --git a/sum.1 b/sum.1 @@ -6,11 +6,27 @@ .Nd returns the sum for each column .Sh SYNOPSIS .Nm +.Op Fl f Ar fmtstr +.Op Fl h .Sh DESCRIPTION .Nm returns the numerical sum for each column in standard input. Input fields must be tab-separated and each line must contain the same number of fields. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl f Ar fmtstr +Formatting string to use as documented in +.Xr printf 3 . +When including a format specifier (%..), only use forms that are +compatible with +.Vt double +types. +The default format string is '%.17g'. +.It Fl h +Show usage information and exit. +.El .Sh EXAMPLES .Dl $ printf '1\et2\et3\en4\et5\et6\en' | sum .Dl 5 7 9 diff --git a/sum.c b/sum.c @@ -2,19 +2,45 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <limits.h> +#include "arg.h" #include "util.h" +char *argv0; + +static void +usage(void) +{ + errx(1, "usage: %s [-f fmtstr] [-h] ", argv0); +} + int -main(void) +main(int argc, char *argv[]) { + int ret; size_t i = 0, nf = 0, nr = 0, linesize = 0; - char *line = NULL, *data = NULL; + char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g"; double val, *vals = NULL; if (pledge("stdio", NULL) == -1) err(2, "pledge"); + ARGBEGIN { + case 'f': + ret = snprintf(fmtstr, sizeof(fmtstr), "%s", EARGF(usage())); + if (ret < 0 || (size_t)ret >= sizeof(fmtstr)) + errx(1, "%s: could not write fmtstr", __func__); + break; + case 'h': + usage(); + break; + default: + usage(); + } ARGEND; + if (argc > 0) + usage(); + while (getline(&line, &linesize, stdin) > 0) { if (nr == 0) if ((nf = allocarr(&vals, line, linesize)) == 0) @@ -29,7 +55,7 @@ main(void) } nr++; } - printarr(vals, nf); + printfarr(fmtstr, vals, nf); free(line); free(vals); diff --git a/util.c b/util.c @@ -44,6 +44,19 @@ printarr(double *arr, size_t len) puts(""); } +void +printfarr(char *fmtstr, double *arr, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + printf(fmtstr, arr[i]); + if (i < len) + printf(DELIMSTR); + } + puts(""); +} + size_t fscanmatrix(FILE *stream, double ***arr, size_t *nf) { diff --git a/util.h b/util.h @@ -22,6 +22,7 @@ void * xreallocarray(void *m, size_t n, size_t s); size_t allocarr(double **arr, const char *str, size_t maxlen); int scannextval(char **str, double *val); void printarr(double *arr, size_t len); +void printfarr(char *fmtstr, double *arr, size_t len); size_t fscanmatrix(FILE *stream, double ***arr, size_t *nf); #endif