| treimplement max(1), mean(1), min(1), and sum(1) in C - numtools - perform nume… | |
| git clone git://src.adamsgaard.dk/numtools | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| commit c0672a06ab06ee7def7d9acd6b728836f6de7397 | |
| parent 5ef38a38146fe0d02f11b47687ea034699307c6f | |
| Author: Anders Damsgaard <[email protected]> | |
| Date: Tue, 31 Aug 2021 14:39:37 +0200 | |
| reimplement max(1), mean(1), min(1), and sum(1) in C | |
| Diffstat: | |
| M Makefile | 30 ++++++++++++++++++------------ | |
| D max | 14 -------------- | |
| A max.c | 38 +++++++++++++++++++++++++++++… | |
| D mean | 13 ------------- | |
| A mean.c | 41 +++++++++++++++++++++++++++++… | |
| D min | 14 -------------- | |
| A min.c | 38 +++++++++++++++++++++++++++++… | |
| D sum | 13 ------------- | |
| A sum.c | 39 +++++++++++++++++++++++++++++… | |
| A util.c | 47 +++++++++++++++++++++++++++++… | |
| M util.h | 4 ++++ | |
| 11 files changed, 225 insertions(+), 66 deletions(-) | |
| --- | |
| diff --git a/Makefile b/Makefile | |
| t@@ -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\ | |
| t@@ -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 $< | |
| t@@ -83,13 +88,14 @@ uninstall: | |
| dist: | |
| rm -rf "${NAME}-${VERSION}" | |
| mkdir -p "${NAME}-${VERSION}" | |
| - cp -rf ${MAN1} ${DOC} ${SRC} ${COMPATSRC} ${SCRIPTS} "${NAME}-${VERSIO… | |
| + 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 | |
| t@@ -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 | |
| t@@ -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",… | |
| + 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 | |
| t@@ -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 | |
| t@@ -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",… | |
| + 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 | |
| t@@ -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 | |
| t@@ -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",… | |
| + 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 | |
| t@@ -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 | |
| t@@ -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",… | |
| + 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 | |
| t@@ -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 | |
| t@@ -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 |