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 c0672a06ab06ee7def7d9acd6b728836f6de7397
parent 5ef38a38146fe0d02f11b47687ea034699307c6f
Author: Anders Damsgaard <anders@adamsgaard.dk>
Date:   Tue, 31 Aug 2021 14:39:37 +0200

reimplement max(1), mean(1), min(1), and sum(1) in C

Diffstat:
MMakefile | 30++++++++++++++++++------------
Dmax | 14--------------
Amax.c | 38++++++++++++++++++++++++++++++++++++++
Dmean | 13-------------
Amean.c | 41+++++++++++++++++++++++++++++++++++++++++
Dmin | 14--------------
Amin.c | 38++++++++++++++++++++++++++++++++++++++
Dsum | 13-------------
Asum.c | 39+++++++++++++++++++++++++++++++++++++++
Autil.c | 47+++++++++++++++++++++++++++++++++++++++++++++++
Mutil.h | 4++++
11 files changed, 225 insertions(+), 66 deletions(-)

diff --git a/Makefile b/Makefile @@ -8,18 +8,19 @@ PREFIX = /usr/local MANPREFIX = ${PREFIX}/man DOCPREFIX = ${PREFIX}/share/doc/${NAME} -SCRIPTS =\ - histpdf\ +BIN =\ max\ mean\ min\ + rangetest\ sum\ - transpose\ -BIN =\ - rangetest\ +SCRIPTS =\ + histpdf\ + transpose\ -SRC = ${BIN:=.c} +SRC =\ + util.c COMPATSRC =\ strnlen.c\ @@ -45,14 +46,18 @@ DOC =\ all: ${BIN} -${BIN}: ${LIB} ${@:=.o} - OBJ = ${SRC:.c=.o} ${COMPATOBJ} ${OBJ}: ${HDR} -.o: - ${CC} -o $@ $< ${_LDFLAGS} ${LIB} +max: max.o +mean: mean.o +min: min.o +rangetest: rangetest.o +sum: sum.o + +${BIN}: ${LIB} ${OBJ} + ${CC} ${_LDFLAGS} -o $@ ${@:=.o} ${OBJ} .c.o: ${CC} ${_CFLAGS} ${_CPPFLAGS} -o $@ -c $< @@ -83,13 +88,14 @@ uninstall: dist: rm -rf "${NAME}-${VERSION}" mkdir -p "${NAME}-${VERSION}" - cp -rf ${MAN1} ${DOC} ${SRC} ${COMPATSRC} ${SCRIPTS} "${NAME}-${VERSION}" + cp -rf ${MAN1} ${DOC} ${BIN:=.c} ${SRC} ${COMPATSRC} ${SCRIPTS} \ + Makefile "${NAME}-${VERSION}" # make tarball tar cf - "${NAME}-${VERSION}" | \ gzip -c > "${NAME}-${VERSION}.tar.gz" rm -rf "${NAME}-${VERSION}" clean: - rm -f ${BIN} ${OBJ} ${LIB} + rm -f ${BIN} ${BIN:=.o} ${OBJ} ${LIB} .PHONY: install uninstall dist clean diff --git a/max b/max @@ -1,14 +0,0 @@ -#!/usr/bin/awk -f -{ - for (i = 1; i <= NF; i++) - if (NR == 1 || $i > max[i]) - max[i] = $i -} -END { - for (i = 1; i <= NF; i++) { - printf("%g", max[i]) - if (i < NF) - printf("\t") - } - printf("\n") -} diff --git a/max.c b/max.c @@ -0,0 +1,38 @@ +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "util.h" + +int +main(void) +{ + size_t i = 0, nf = 0, nr = 0, linesize = 0; + char *line = NULL, *data = NULL; + double val, *vals = NULL; + int offset; + + if (pledge("stdio", NULL) == -1) + err(2, "pledge"); + + while (getline(&line, &linesize, stdin) > 0) { + if (nr == 0) + if ((nf = allocarr(&vals, line, linesize)) == 0) + errx(1, "no fields in input"); + data = line; + for (i = 0; i < nf; i++) { + if (!scannextval(&data, &val)) + errx(1, "could not parse line %ld, field %ld", nr + 1, i + 1); + if (nr == 0 || val > vals[i]) + vals[i] = val; + } + nr++; + } + printarr(vals, nf); + + free(line); + free(vals); + + return 0; +} diff --git a/mean b/mean @@ -1,13 +0,0 @@ -#!/usr/bin/awk -f -{ - for (i = 1; i <= NF; i++) - sum[i] += $i -} -END { - for (i = 1; i <= NF; i++) { - printf("%g", sum[i] / NR) - if (i < NF) - printf("\t") - } - printf("\n") -} diff --git a/mean.c b/mean.c @@ -0,0 +1,41 @@ +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "util.h" + +int +main(void) +{ + size_t i = 0, nf = 0, nr = 0, linesize = 0; + char *line = NULL, *data = NULL; + double val, *vals = NULL; + int offset; + + if (pledge("stdio", NULL) == -1) + err(2, "pledge"); + + while (getline(&line, &linesize, stdin) > 0) { + if (nr == 0) + if ((nf = allocarr(&vals, line, linesize)) == 0) + errx(1, "no fields in input"); + data = line; + for (i = 0; i < nf; i++) { + if (!scannextval(&data, &val)) + errx(1, "could not parse line %ld, field %ld", nr + 1, i + 1); + if (nr == 0) + vals[i] = 0.0; + vals[i] += val; + } + nr++; + } + for (i = 0; i < nf; i++) + vals[i] /= (double)nr; + printarr(vals, nf); + + free(line); + free(vals); + + return 0; +} diff --git a/min b/min @@ -1,14 +0,0 @@ -#!/usr/bin/awk -f -{ - for (i = 1; i <= NF; i++) - if (NR == 1 || $i < min[i]) - min[i] = $i -} -END { - for (i = 1; i <= NF; i++) { - printf("%g", min[i]) - if (i < NF) - printf("\t") - } - printf("\n") -} diff --git a/min.c b/min.c @@ -0,0 +1,38 @@ +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "util.h" + +int +main(void) +{ + size_t i = 0, nf = 0, nr = 0, linesize = 0; + char *line = NULL, *data = NULL; + double val, *vals = NULL; + int offset; + + if (pledge("stdio", NULL) == -1) + err(2, "pledge"); + + while (getline(&line, &linesize, stdin) > 0) { + if (nr == 0) + if ((nf = allocarr(&vals, line, linesize)) == 0) + errx(1, "no fields in input"); + data = line; + for (i = 0; i < nf; i++) { + if (!scannextval(&data, &val)) + errx(1, "could not parse line %ld, field %ld", nr + 1, i + 1); + if (nr == 0 || val < vals[i]) + vals[i] = val; + } + nr++; + } + printarr(vals, nf); + + free(line); + free(vals); + + return 0; +} diff --git a/sum b/sum @@ -1,13 +0,0 @@ -#!/usr/bin/awk -f -{ - for (i = 1; i <= NF; i++) - sum[i] += $i -} -END { - for (i = 1; i <= NF; i++) { - printf("%g", sum[i]) - if (i < NF) - printf("\t") - } - printf("\n") -} diff --git a/sum.c b/sum.c @@ -0,0 +1,39 @@ +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "util.h" + +int +main(void) +{ + size_t i = 0, nf = 0, nr = 0, linesize = 0; + char *line = NULL, *data = NULL; + double val, *vals = NULL; + int offset; + + if (pledge("stdio", NULL) == -1) + err(2, "pledge"); + + while (getline(&line, &linesize, stdin) > 0) { + if (nr == 0) + if ((nf = allocarr(&vals, line, linesize)) == 0) + errx(1, "no fields in input"); + data = line; + for (i = 0; i < nf; i++) { + if (!scannextval(&data, &val)) + errx(1, "could not parse line %ld, field %ld", nr + 1, i + 1); + if (nr == 0) + vals[i] = 0.0; + vals[i] += val; + } + nr++; + } + printarr(vals, nf); + + free(line); + free(vals); + + return 0; +} diff --git a/util.c b/util.c @@ -0,0 +1,47 @@ +#include <err.h> +#include <stdlib.h> +#include <stdio.h> + +#define DELIM '\t' +#define DELIMSTR "\t" + +size_t +allocarr(double **arr, const char *str, size_t maxlen) +{ + size_t i, nf = 0; + + if (maxlen > 0) + nf = 1; + for (i = 0; i < maxlen && str[i] != '\0'; i++) + if (str[i] == DELIM) + nf++; + if (!(*arr = calloc(nf, sizeof(double)))) + err(1, "calloc"); + + return nf; +} + +int +scannextval(char **str, double *val) +{ + int offset; + + if (sscanf(*str, "%lg%n", val, &offset) != 1) + return 0; + *str += offset; + + return 1; +} + +void +printarr(double *arr, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + printf("%g", arr[i]); + if (i < len) + printf(DELIMSTR); + } + puts(""); +} diff --git a/util.h b/util.h @@ -14,4 +14,8 @@ size_t strlcpy(char *dst, const char *src, size_t dsize); #undef strnlen size_t strnlen(const char *str, size_t maxlen); +size_t allocarr(double **arr, const char *str, size_t maxlen); +int scannextval(char **str, double *val); +void printarr(double *arr, size_t len); + #endif