| tuse safe formatting parameters and option parsing - numtools - perform numeric… | |
| git clone git://src.adamsgaard.dk/numtools | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| commit 8787e852ca96ee9c18d4ed1a45016996e464940a | |
| parent d206d176dbb5704fda2d5cc33010f54b8f36ff38 | |
| Author: Anders Damsgaard <[email protected]> | |
| Date: Wed, 11 May 2022 14:57:18 +0200 | |
| use safe formatting parameters and option parsing | |
| Diffstat: | |
| M max.1 | 29 ++++++++++++++++------------- | |
| M max.c | 45 ++++++++++++++++++-----------… | |
| M mean.1 | 29 ++++++++++++++++------------- | |
| M mean.c | 45 ++++++++++++++++++-----------… | |
| M min.1 | 29 ++++++++++++++++------------- | |
| M min.c | 45 ++++++++++++++++++-----------… | |
| M randcounts.1 | 38 +++++++++++++++++++++++------… | |
| M randcounts.c | 98 ++++++++++++++++++-----------… | |
| M randnum.c | 8 ++++---- | |
| M range.1 | 61 ++++++++++++++++-------------… | |
| M range.c | 107 ++++++++++++++++++-----------… | |
| M rangetest.c | 40 +++++++++++++++--------------… | |
| M stddev.1 | 27 +++++++++++++++------------ | |
| M stddev.c | 52 ++++++++++++++++++-----------… | |
| M stdvar.1 | 29 ++++++++++++++++------------- | |
| M stdvar.c | 52 ++++++++++++++++++-----------… | |
| M sum.1 | 29 ++++++++++++++++------------- | |
| M sum.c | 45 ++++++++++++++++++-----------… | |
| M transpose.1 | 6 +++--- | |
| M util.c | 9 ++++----- | |
| M util.h | 2 +- | |
| 21 files changed, 469 insertions(+), 356 deletions(-) | |
| --- | |
| diff --git a/max.1 b/max.1 | |
| t@@ -6,8 +6,9 @@ | |
| .Nd returns the maximum value for each column | |
| .Sh SYNOPSIS | |
| .Nm | |
| -.Op Fl f Ar fmtstr | |
| -.Op Fl h | |
| +.Op Fl d Ar delimstr | |
| +.Op Fl n | |
| +.Op Fl p Ar prec | |
| .Sh DESCRIPTION | |
| .Nm | |
| returns the maximum numerical value for each column in standard | |
| t@@ -17,20 +18,22 @@ 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. | |
| +.It Fl d Ar delimstr | |
| +Separate output values by | |
| +.Ar delimstr . | |
| +The default delimiter is tab characters. | |
| +.It Fl n | |
| +Do not print a newline after the final value. | |
| +.It Fl p prec | |
| +Print the output values with | |
| +.Ar prec | |
| +digits of precision. | |
| +By default, the output is printed with 17 digits of precision, which is | |
| +full double precision on 64-bit systems. | |
| .El | |
| .Sh EXAMPLES | |
| .Dl $ printf '1\et2\et3\en4\et5\et6\en' | max | |
| -.Dl 4 5 6 | |
| +.Dl 4 5 6 | |
| .Sh SEE ALSO | |
| .Xr mean 1 , | |
| .Xr min 1 , | |
| diff --git a/max.c b/max.c | |
| t@@ -4,40 +4,45 @@ | |
| #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); | |
| + errx(1, "usage: max [-d delimstr] [-n] [-p prec]"); | |
| } | |
| int | |
| main(int argc, char *argv[]) | |
| { | |
| - int ret; | |
| + int ch, prec = 17, finalnl = 1; | |
| size_t i = 0, nf = 0, nr = 0, linesize = 0; | |
| - char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g"; | |
| + char *line = NULL, *data = NULL, *delimstr = "\t"; | |
| + const char *errstr; | |
| 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; | |
| + while ((ch = getopt(argc, argv, "d:np:")) != -1) { | |
| + switch (ch) { | |
| + case 'd': | |
| + delimstr = optarg; | |
| + break; | |
| + case 'n': | |
| + finalnl = 0; | |
| + break; | |
| + case 'p': | |
| + prec = strtonum(optarg, 0, INT_MAX, &errstr); | |
| + if (errstr != NULL) | |
| + errx(1, "bad precision value, %s: %s", errstr,… | |
| + break; | |
| + default: | |
| + usage(); | |
| + } | |
| + } | |
| + argc -= optind; | |
| + /*argv += optind;*/ | |
| if (argc > 0) | |
| usage(); | |
| t@@ -54,7 +59,9 @@ main(int argc, char *argv[]) | |
| } | |
| nr++; | |
| } | |
| - printfarr(fmtstr, vals, nf); | |
| + printfarr(delimstr, prec, vals, nf); | |
| + if (finalnl) | |
| + putchar('\n'); | |
| free(line); | |
| free(vals); | |
| diff --git a/mean.1 b/mean.1 | |
| t@@ -6,8 +6,9 @@ | |
| .Nd returns the average value for each column | |
| .Sh SYNOPSIS | |
| .Nm | |
| -.Op Fl f Ar fmtstr | |
| -.Op Fl h | |
| +.Op Fl d Ar delimstr | |
| +.Op Fl n | |
| +.Op Fl p Ar prec | |
| .Sh DESCRIPTION | |
| .Nm | |
| returns the mean numerical value for each column in standard input. | |
| t@@ -16,20 +17,22 @@ 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. | |
| +.It Fl d Ar delimstr | |
| +Separate output values by | |
| +.Ar delimstr . | |
| +The default delimiter is tab characters. | |
| +.It Fl n | |
| +Do not print a newline after the final value. | |
| +.It Fl p prec | |
| +Print the output values with | |
| +.Ar prec | |
| +digits of precision. | |
| +By default, the output is printed with 17 digits of precision, which is | |
| +full double precision on 64-bit systems. | |
| .El | |
| .Sh EXAMPLES | |
| .Dl $ printf '1\et2\et3\en4\et5\et6\en' | mean | |
| -.Dl 2.5 3.5 4.5 | |
| +.Dl 2.5 3.5 4.5 | |
| .Sh SEE ALSO | |
| .Xr max 1 , | |
| .Xr min 1 , | |
| diff --git a/mean.c b/mean.c | |
| t@@ -4,40 +4,45 @@ | |
| #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); | |
| + errx(1, "usage: mean [-d delimstr] [-n] [-p prec]"); | |
| } | |
| int | |
| main(int argc, char *argv[]) | |
| { | |
| - int ret; | |
| + int ch, prec = 17, finalnl = 1; | |
| size_t i = 0, nf = 0, nr = 0, linesize = 0; | |
| - char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g"; | |
| + char *line = NULL, *data = NULL, *delimstr = "\t"; | |
| + const char *errstr; | |
| 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; | |
| + while ((ch = getopt(argc, argv, "d:np:")) != -1) { | |
| + switch (ch) { | |
| + case 'd': | |
| + delimstr = optarg; | |
| + break; | |
| + case 'n': | |
| + finalnl = 0; | |
| + break; | |
| + case 'p': | |
| + prec = strtonum(optarg, 0, INT_MAX, &errstr); | |
| + if (errstr != NULL) | |
| + errx(1, "bad precision value, %s: %s", errstr,… | |
| + break; | |
| + default: | |
| + usage(); | |
| + } | |
| + } | |
| + argc -= optind; | |
| + /*argv += optind;*/ | |
| if (argc > 0) | |
| usage(); | |
| t@@ -57,7 +62,9 @@ main(int argc, char *argv[]) | |
| } | |
| for (i = 0; i < nf; i++) | |
| vals[i] /= (double)nr; | |
| - printfarr(fmtstr, vals, nf); | |
| + printfarr(delimstr, prec, vals, nf); | |
| + if (finalnl) | |
| + putchar('\n'); | |
| free(line); | |
| free(vals); | |
| diff --git a/min.1 b/min.1 | |
| t@@ -6,8 +6,9 @@ | |
| .Nd returns the minimum value for each column | |
| .Sh SYNOPSIS | |
| .Nm | |
| -.Op Fl f Ar fmtstr | |
| -.Op Fl h | |
| +.Op Fl d Ar delimstr | |
| +.Op Fl n | |
| +.Op Fl p Ar prec | |
| .Sh DESCRIPTION | |
| .Nm | |
| returns the minimum numerical value for each column in standard | |
| t@@ -17,20 +18,22 @@ 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. | |
| +.It Fl d Ar delimstr | |
| +Separate output values by | |
| +.Ar delimstr . | |
| +The default delimiter is tab characters. | |
| +.It Fl n | |
| +Do not print a newline after the final value. | |
| +.It Fl p prec | |
| +Print the output values with | |
| +.Ar prec | |
| +digits of precision. | |
| +By default, the output is printed with 17 digits of precision, which is | |
| +full double precision on 64-bit systems. | |
| .El | |
| .Sh EXAMPLES | |
| .Dl $ printf '1\et2\et3\en4\et5\et6\en' | min | |
| -.Dl 1 2 3 | |
| +.Dl 1 2 3 | |
| .Sh SEE ALSO | |
| .Xr max 1 , | |
| .Xr mean 1 , | |
| diff --git a/min.c b/min.c | |
| t@@ -4,40 +4,45 @@ | |
| #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); | |
| + errx(1, "usage: max [-d delimstr] [-n] [-p prec]"); | |
| } | |
| int | |
| main(int argc, char *argv[]) | |
| { | |
| - int ret; | |
| + int ch, prec = 17, finalnl = 1; | |
| size_t i = 0, nf = 0, nr = 0, linesize = 0; | |
| - char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g"; | |
| + char *line = NULL, *data = NULL, *delimstr = "\t"; | |
| + const char *errstr; | |
| 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; | |
| + while ((ch = getopt(argc, argv, "d:np:")) != -1) { | |
| + switch (ch) { | |
| + case 'd': | |
| + delimstr = optarg; | |
| + break; | |
| + case 'n': | |
| + finalnl = 0; | |
| + break; | |
| + case 'p': | |
| + prec = strtonum(optarg, -10, INT_MAX, &errstr); | |
| + if (errstr != NULL) | |
| + errx(1, "bad precision value, %s: %s", errstr,… | |
| + break; | |
| + default: | |
| + usage(); | |
| + } | |
| + } | |
| + argc -= optind; | |
| + /*argv += optind;*/ | |
| if (argc > 0) | |
| usage(); | |
| t@@ -54,7 +59,9 @@ main(int argc, char *argv[]) | |
| } | |
| nr++; | |
| } | |
| - printfarr(fmtstr, vals, nf); | |
| + printfarr(delimstr, prec, vals, nf); | |
| + if (finalnl) | |
| + putchar('\n'); | |
| free(line); | |
| free(vals); | |
| diff --git a/randcounts.1 b/randcounts.1 | |
| t@@ -6,8 +6,10 @@ | |
| .Nd produces random counts in weighted bins | |
| .Sh SYNOPSIS | |
| .Nm | |
| -.Op Fl h | |
| -.Op Fl n Ar num | |
| +.Op Fl d Ar delimstr | |
| +.Op Fl n | |
| +.Op Fl N Ar num | |
| +.Op Fl p Ar prec | |
| .Op Fl r Ar repeats | |
| .Op Fl R | |
| .Op Fl s Ar seed | |
| t@@ -31,15 +33,28 @@ Output consists of the number of points per bin, in tab-se… | |
| .Pp | |
| The options are as follows: | |
| .Bl -tag -width Ds | |
| -.It Fl h | |
| -Show usage information. | |
| -.It Fl n Ar num | |
| +.It Fl d Ar delimstr | |
| +Separate output values by | |
| +.Ar delimstr . | |
| +The default delimiter is tab characters. | |
| +.It Fl n | |
| +Do not print a newline after the final value. | |
| +.It Fl N Ar num | |
| Number of points to place in the bins. | |
| The default is 1. | |
| .It Fl r Ar repeats | |
| Repeat the binning several times, with one realization per line of output. | |
| .It Fl R | |
| Show the output as ratios (in the range [0;1]) instead of counts. | |
| +.It Fl p prec | |
| +Print the output values with | |
| +.Ar prec | |
| +digits of precision. | |
| +This option only applies if called with the | |
| +.Fl R | |
| +option. | |
| +By default, the output is printed with 17 digits of precision, which is | |
| +full double precision on 64-bit systems. | |
| .It Fl s Ar seed | |
| Seed the pseudo-random number generator with this value, which is used | |
| to generate reproducable binning. | |
| t@@ -48,15 +63,18 @@ to generate reproducable binning. | |
| Put one point in four bins with equal probability (25%). | |
| Due to the randomness, your output may differ: | |
| .Dl $ randcounts 0.25 0.25 0.25 0.25 | |
| -.Dl 0 1 0 0 | |
| +.Dl 0 1 0 0 | |
| .Pp | |
| -Put 100 points in two bins with 75% and 25% probability, respectively: | |
| -.Dl $ randcounts -n 100 0.75 0.25 | |
| +Put 100 points in two bins with 75% and 25% probability, respectively, | |
| +and print the count ratios for each bin: | |
| +.Dl $ randcounts -N 100 -R 0.75 0.25 | |
| +.Dl 0.72999999999999998 0.27000000000000002 | |
| .Pp | |
| -Put 100 points in three equal bins 1000 times, and calculate the average bin s… | |
| +Put 100 points in three equal bins 1000 times, and calculate the average | |
| +bin sizes with | |
| .Xr mean 1 : | |
| .Dl $ randcounts -n 100 -r 1000 0.333 0.333 0.334 | mean | |
| -.Dl 33.067 32.82 34.113 | |
| +.Dl 33.067 32.82 34.113 | |
| .Sh SEE ALSO | |
| .Xr mean 1 , | |
| .Xr range 1 , | |
| diff --git a/randcounts.c b/randcounts.c | |
| t@@ -5,68 +5,85 @@ | |
| #include <string.h> | |
| #include <math.h> | |
| #include <sys/time.h> | |
| +#include <unistd.h> | |
| -#include "arg.h" | |
| #include "util.h" | |
| -char *argv0; | |
| - | |
| static void | |
| usage(void) | |
| { | |
| - errx(1, "usage: %s [-h] [-n num] [-r repeats] [-R] [-s seed] " | |
| - "weight1 [weight2 ...]\n", argv0); | |
| + errx(1, "usage: randcounts [-d delimstr] [-n] [-N num] [-p prec]" | |
| + "[-r repeats] [-R] [-s seed] weight1 [weight2 ...]"); | |
| } | |
| int | |
| main(int argc, char *argv[]) | |
| { | |
| - int i, s = 0, N; | |
| + int i, ch, nbins, prec = 17, finalnl = 1, s = 0; | |
| long j, seed, *counts = NULL, n = 1, r, repeats = 1, ratio = 0; | |
| double val = 0.0, weightsum = 0.0, *weights = NULL; | |
| + char *delimstr = "\t"; | |
| + const char *errstr; | |
| struct timeval t1; | |
| if (pledge("stdio", NULL) == -1) | |
| err(2, "pledge"); | |
| - ARGBEGIN { | |
| - case 'h': | |
| - usage(); | |
| - break; | |
| - case 'n': | |
| - n = atol(EARGF(usage())); | |
| - break; | |
| - case 'r': | |
| - repeats = atol(EARGF(usage())); | |
| - break; | |
| - case 'R': | |
| - ratio = 1; | |
| - break; | |
| - case 's': | |
| - s = 1; | |
| - seed = atol(EARGF(usage())); | |
| - break; | |
| - default: | |
| - usage(); | |
| - } ARGEND; | |
| - | |
| + while ((ch = getopt(argc, argv, "d:nN:r:Rp:s:")) != -1) { | |
| + switch (ch) { | |
| + case 'd': | |
| + delimstr = optarg; | |
| + break; | |
| + case 'n': | |
| + finalnl = 0; | |
| + break; | |
| + case 'N': | |
| + n = strtonum(optarg, 0, LONG_MAX, &errstr); | |
| + if (errstr != NULL) | |
| + errx(1, "bad num value, %s: %s", errstr, optar… | |
| + break; | |
| + case 'r': | |
| + repeats = strtonum(optarg, 0, LONG_MAX, &errstr); | |
| + if (errstr != NULL) | |
| + errx(1, "bad repeats value, %s: %s", errstr, o… | |
| + break; | |
| + case 'R': | |
| + ratio = 1; | |
| + break; | |
| + case 'p': | |
| + prec = strtonum(optarg, 0, INT_MAX, &errstr); | |
| + if (errstr != NULL) | |
| + errx(1, "bad precision value, %s: %s", errstr,… | |
| + break; | |
| + case 's': | |
| + seed = strtonum(optarg, 0, INT_MAX, &errstr); | |
| + if (errstr != NULL) | |
| + errx(1, "bad seed value, %s: %s", errstr, opta… | |
| + break; | |
| + default: | |
| + usage(); | |
| + } | |
| + } | |
| + argc -= optind; | |
| + argv += optind; | |
| if (argc < 1) | |
| usage(); | |
| - N = argc; | |
| - if (!(weights = calloc(N, sizeof(double))) || | |
| - !(counts = calloc(N, sizeof(long)))) | |
| + nbins = argc; | |
| + if (!(weights = calloc(nbins, sizeof(double))) || | |
| + !(counts = calloc(nbins, sizeof(long)))) | |
| err(1, "calloc"); | |
| - for (i = 0; i < N; i++) { | |
| - weights[i] = atof(argv[i]); | |
| + for (i = 0; i < nbins; i++) { | |
| + if (!sscanf(argv[i], "%lf", &weights[i])) | |
| + errx(1, "bad weight value: %s", argv[i]); | |
| if (weights[i] <= 0.0) | |
| errx(1, "weight %d is not positive (%g)", i, weights[i… | |
| if (weights[i] > 1.0) | |
| errx(1, "weight %d is greater than 1 (%g)", i, weights… | |
| } | |
| - for (i = 0; i < N; i++) | |
| + for (i = 0; i < nbins; i++) | |
| weightsum += weights[i]; | |
| if (fabs(weightsum - 1.0) > 1e-3) | |
| errx(1, "weights do not sum to 1 (%g)", weightsum); | |
| t@@ -83,12 +100,12 @@ main(int argc, char *argv[]) | |
| #endif | |
| for (r = 0; r < repeats; r++) { | |
| - for (i = 0; i < N; i++) | |
| + for (i = 0; i < nbins; i++) | |
| counts[i] = 0; | |
| for (j = 0; j < n; j++) { | |
| val = drand48(); | |
| weightsum = 0.0; | |
| - for (i = 0; i < N; i++) { | |
| + for (i = 0; i < nbins; i++) { | |
| weightsum += weights[i]; | |
| if (val <= weightsum) { | |
| counts[i]++; | |
| t@@ -96,15 +113,16 @@ main(int argc, char *argv[]) | |
| } | |
| } | |
| } | |
| - for (i = 0; i < N; i++) { | |
| + for (i = 0; i < nbins; i++) { | |
| if (ratio) | |
| - printf("%.17g", (double)counts[i] / n); | |
| + printf("%.*g", prec, (double)counts[i] / n); | |
| else | |
| printf("%ld", counts[i]); | |
| - if (i < N - 1) | |
| - putchar('\t'); | |
| + if (i < nbins - 1) | |
| + fputs(delimstr, stdout); | |
| else | |
| - putchar('\n'); | |
| + if (finalnl) | |
| + putchar('\n'); | |
| } | |
| } | |
| diff --git a/randnum.c b/randnum.c | |
| t@@ -20,9 +20,9 @@ usage(void) | |
| int | |
| main(int argc, char *argv[]) | |
| { | |
| - int i, ret, ch, s = 0, prec = 17, finalnl = 1; | |
| - long j, seed, n = 1; | |
| - double val, minv = 0.0, maxv = 1.0; | |
| + int i, ch, s = 0, prec = 17, finalnl = 1; | |
| + long seed, n = 1; | |
| + double minv = 0.0, maxv = 1.0; | |
| char *delimstr = "\n"; | |
| const char *errstr; | |
| struct timeval t1; | |
| t@@ -44,7 +44,7 @@ main(int argc, char *argv[]) | |
| errx(1, "bad num value, %s: %s", errstr, optar… | |
| break; | |
| case 'p': | |
| - prec = strtonum(optarg, -10, INT_MAX, &errstr); | |
| + prec = strtonum(optarg, 0, INT_MAX, &errstr); | |
| if (errstr != NULL) | |
| errx(1, "bad precision value, %s: %s", errstr,… | |
| break; | |
| diff --git a/range.1 b/range.1 | |
| t@@ -7,11 +7,12 @@ | |
| .Sh SYNOPSIS | |
| .Nm | |
| .Op Fl b | |
| +.Op Fl d Ar delimstr | |
| .Op Fl e | |
| -.Op Fl f Ar fmtstr | |
| -.Op Fl h | |
| .Op Fl l | |
| -.Op Fl n Ar num | |
| +.Op Fl n | |
| +.Op Fl N Ar num | |
| +.Op Fl p Ar prec | |
| .Op Fl s | |
| .Oo | |
| .Op Ar min_val | |
| t@@ -45,6 +46,10 @@ as the first value, making it a half-open interval | |
| .Ar max_val ], | |
| or an entirely open interval when combined with | |
| .Op Ar e . | |
| +.It Fl d Ar delimstr | |
| +Separate output values by | |
| +.Ar delimstr . | |
| +The default delimiter is newlines. | |
| .It Fl e | |
| Do not include | |
| .Ar max_val | |
| t@@ -53,54 +58,50 @@ as the last value, making it a half-open interval | |
| .Ar max_val [, | |
| or an entirely open interval when combined with | |
| .Op Ar b . | |
| -.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. | |
| .It Fl l | |
| Produce output with even intervals in logarithmic space between 10^min_val | |
| and 10^max_val. | |
| -.It Fl n Ar num | |
| +.It Fl n | |
| +Do not print a newline after the final value. | |
| +.It Fl N Ar num | |
| Number of values to produce within the specified range. | |
| The default is 10. | |
| +.It Fl p prec | |
| +Print the output values with | |
| +.Ar prec | |
| +digits of precision. | |
| +By default, the output is printed with 17 digits of precision, which is | |
| +full double precision on 64-bit systems. | |
| .It Fl s | |
| -Print the spacing between numbers and exit. | |
| +Print the numerical spacing between numbers and exit. | |
| .El | |
| .Sh EXAMPLES | |
| Generate four equally-spaced numbers in the closed default range [0;1]: | |
| -.Dl $ range -n 4 -f '%.17g\en' 0 1 | |
| +.Dl $ range -N 4 | |
| .Dl 0 | |
| .Dl 0.33333333333333331 | |
| .Dl 0.66666666666666663 | |
| .Dl 1 | |
| .Pp | |
| Generate four numbers in the range ]0;1[: | |
| -.Dl $ range -b -e -n 4 0 1 | |
| -.Dl 0.2 | |
| -.Dl 0.4 | |
| -.Dl 0.6 | |
| -.Dl 0.8 | |
| +.Dl $ range -be -N 4 | |
| +.Dl 0.20000000000000001 | |
| +.Dl 0.40000000000000002 | |
| +.Dl 0.60000000000000009 | |
| +.Dl 0.80000000000000004 | |
| .Pp | |
| -Repeat and modify a string three times: | |
| -.Dl $ range -n 3 -f 'The best number is %.0g' 1 3 | |
| -.Dl The best number is 1 | |
| -.Dl The best number is 2 | |
| -.Dl The best number is 3 | |
| +Generate three space-separated numbers: | |
| +.Dl $ range -d' ' -N 3 1 3 | |
| +.Dl 1 2 3 | |
| .Pp | |
| Generate three numbers evenly distributed in logspace from 10^0 to 10^2: | |
| -.Dl $ range -l -n 3 0 2 | |
| +.Dl $ range -l -N 3 0 2 | |
| .Dl 1 | |
| .Dl 10 | |
| .Dl 100 | |
| .Pp | |
| Generate three numbers in the range [-2;-1]: | |
| -.Dl $ range -n 3 -- -2 -1 | |
| +.Dl $ range -N 3 -- -2 -1 | |
| .Dl -2 | |
| .Dl -1.5 | |
| .Dl -1 | |
| t@@ -108,7 +109,7 @@ Generate three numbers in the range [-2;-1]: | |
| .Xr max 1 , | |
| .Xr mean 1 , | |
| .Xr min 1 , | |
| -.Xr rangetest 1 , | |
| -.Xr sum 1 | |
| +.Xr randnum 1 , | |
| +.Xr rangetest 1 | |
| .Sh AUTHORS | |
| .An Anders Damsgaard Aq Mt [email protected] | |
| diff --git a/range.c b/range.c | |
| t@@ -4,78 +4,95 @@ | |
| #include <limits.h> | |
| #include <string.h> | |
| #include <math.h> | |
| +#include <unistd.h> | |
| -#include "arg.h" | |
| #include "util.h" | |
| -char *argv0; | |
| - | |
| static void | |
| usage(void) | |
| { | |
| - errx(1, "usage: %s [-b] [-e] [-f fmtstr] [-h] [-l] [-n num] [-s] " | |
| - "[[min_val] max_val]\n", argv0); | |
| + errx(1, "usage: range [-b] [-d delimstr] [-e] [-l] [-n] [-N num] " | |
| + "[-p prec] [-s] [[min_val] max_val]"); | |
| } | |
| int | |
| main(int argc, char *argv[]) | |
| { | |
| - int i, ret, n = 10, logrange = 0, openstart = 0, openend = 0, | |
| - reportdx = 0; | |
| - double minv = 0.0, maxv = 1.0, dx; | |
| - char fmtstr[PATH_MAX] = "%.17g"; | |
| + int i, j, ch, n = 10, logrange = 0, openstart = 0, openend = 0, | |
| + prec = 17, finalnl = 1, reportdx = 0; | |
| + double minv = 0.0, maxv = 1.0, dx, val; | |
| + const char *errstr; | |
| + char *delimstr = "\n"; | |
| if (pledge("stdio", NULL) == -1) | |
| err(2, "pledge"); | |
| - ARGBEGIN { | |
| - case 'b': | |
| - openstart = 1; | |
| - break; | |
| - case 'e': | |
| - openend = 1; | |
| - break; | |
| - 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; | |
| - case 'l': | |
| - logrange = 1; | |
| - break; | |
| - case 'n': | |
| - n = atoi(EARGF(usage())); | |
| - break; | |
| - case 's': | |
| - reportdx = 1; | |
| - break; | |
| - default: | |
| - usage(); | |
| - } ARGEND; | |
| - | |
| + while ((ch = getopt(argc, argv, "bd:elnN:p:s")) != -1) { | |
| + switch (ch) { | |
| + case 'b': | |
| + openstart = 1; | |
| + break; | |
| + case 'd': | |
| + delimstr = optarg; | |
| + break; | |
| + case 'e': | |
| + openend = 1; | |
| + break; | |
| + case 'l': | |
| + logrange = 1; | |
| + break; | |
| + case 'n': | |
| + finalnl = 0; | |
| + break; | |
| + case 'N': | |
| + n = strtonum(optarg, 0, LONG_MAX, &errstr); | |
| + if (errstr != NULL) | |
| + errx(1, "bad num value, %s: %s", errstr, optar… | |
| + break; | |
| + case 'p': | |
| + prec = strtonum(optarg, -10, INT_MAX, &errstr); | |
| + if (errstr != NULL) | |
| + errx(1, "bad precision value, %s: %s", errstr,… | |
| + break; | |
| + case 's': | |
| + reportdx = 1; | |
| + break; | |
| + default: | |
| + usage(); | |
| + } | |
| + } | |
| + argc -= optind; | |
| + argv += optind; | |
| if (argc > 2) | |
| usage(); | |
| else if (argc == 2) { | |
| - minv = atof(argv[0]); | |
| - maxv = atof(argv[1]); | |
| + if (!sscanf(argv[0], "%lf", &minv)) | |
| + errx(1, "bad minv value: %s", argv[0]); | |
| + if (!sscanf(argv[1], "%lf", &maxv)) | |
| + errx(1, "bad maxv value: %s", argv[1]); | |
| } else if (argc == 1) | |
| - maxv = atof(argv[0]); | |
| + if (!sscanf(argv[0], "%lf", &maxv)) | |
| + errx(1, "bad maxv value: %s", argv[0]); | |
| dx = (maxv - minv) / (n - 1 + openend + openstart); | |
| if (reportdx) { | |
| - printf(fmtstr, dx); | |
| + printf("%.*g", prec, dx); | |
| + if (finalnl) | |
| + putchar('\n'); | |
| return 0; | |
| } | |
| - for (i = 0 + openstart; i < n + openstart; i++) { | |
| + for (i = 0; i < n; i++) { | |
| + j = i + openstart; | |
| if (logrange) | |
| - printf(fmtstr, pow(10, minv + i * dx)); | |
| + val = pow(10, minv + j * dx); | |
| else | |
| - printf(fmtstr, minv + i * dx); | |
| - putchar('\n'); | |
| + val = minv + j * dx; | |
| + printf("%.*g", prec, val); | |
| + if (i < n - 1) | |
| + fputs(delimstr, stdout); | |
| } | |
| + if (finalnl) | |
| + putchar('\n'); | |
| return 0; | |
| } | |
| diff --git a/rangetest.c b/rangetest.c | |
| t@@ -3,19 +3,17 @@ | |
| #include <err.h> | |
| #include <limits.h> | |
| #include <string.h> | |
| +#include <unistd.h> | |
| -#include "arg.h" | |
| #include "util.h" | |
| #define VALUESTR "@VAL@" | |
| -char *argv0; | |
| - | |
| static void | |
| usage(void) | |
| { | |
| - errx(1, "usage: %s [-h] [-n maxiter] cmd min_val max_val\n" | |
| - "where cmd must contain the string '" VALUESTR "'", argv0); | |
| + errx(1, "usage: rangetest [-n maxiter] cmd min_val max_val\n" | |
| + "where cmd must contain the string '" VALUESTR "'"); | |
| } | |
| static int | |
| t@@ -41,8 +39,7 @@ launch(char *cmd, char *cmd0, double val) | |
| static void | |
| binary_search(char *cmd, char *cmd0, double minv, double maxv, int maxiter) | |
| { | |
| - int minfail, maxfail; | |
| - int iter = 0; | |
| + int minfail, maxfail, iter = 0; | |
| double val; | |
| minfail = launch(cmd, cmd0, minv); | |
| t@@ -76,23 +73,24 @@ binary_search(char *cmd, char *cmd0, double minv, double m… | |
| int | |
| main(int argc, char *argv[]) | |
| { | |
| - int maxiter = 10; | |
| + int ch, maxiter = 10; | |
| double minv, maxv; | |
| char cmd0[PATH_MAX] = "", cmd[PATH_MAX] = ""; | |
| + const char *errstr; | |
| - ARGBEGIN { | |
| - case 'h': | |
| - usage(); | |
| - break; | |
| - case 'n': | |
| - maxiter = atoi(EARGF(usage())); | |
| - if (maxiter < 1) | |
| - errx(1, "maxiter (-n) must be positive"); | |
| - break; | |
| - default: | |
| - usage(); | |
| - } ARGEND; | |
| - | |
| + while ((ch = getopt(argc, argv, "N:")) != -1) { | |
| + switch (ch) { | |
| + case 'N': | |
| + maxiter = strtonum(optarg, 0, INT_MAX, &errstr); | |
| + if (errstr != NULL) | |
| + errx(1, "bad maxiter value, %s: %s", errstr, o… | |
| + break; | |
| + default: | |
| + usage(); | |
| + } | |
| + } | |
| + argc -= optind; | |
| + argv += optind; | |
| if (argc == 3) { | |
| if (strlcpy(cmd0, argv[0], sizeof(cmd0)) >= sizeof(cmd0)) | |
| err(1, "cmd too long"); | |
| diff --git a/stddev.1 b/stddev.1 | |
| t@@ -6,8 +6,9 @@ | |
| .Nd returns the standard deviation for each input column | |
| .Sh SYNOPSIS | |
| .Nm | |
| -.Op Fl f Ar fmtstr | |
| -.Op Fl h | |
| +.Op Fl d Ar delimstr | |
| +.Op Fl n | |
| +.Op Fl p Ar prec | |
| .Op Fl u | |
| .Sh DESCRIPTION | |
| .Nm | |
| t@@ -19,16 +20,18 @@ 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 d Ar delimstr | |
| +Separate output values by | |
| +.Ar delimstr . | |
| +The default delimiter is tab characters. | |
| +.It Fl n | |
| +Do not print a newline after the final value. | |
| +.It Fl p prec | |
| +Print the output values with | |
| +.Ar prec | |
| +digits of precision. | |
| +By default, the output is printed with 17 digits of precision, which is | |
| +full double precision on 64-bit systems. | |
| .It Fl u | |
| Return the uncorrected sample standard deviation instead. | |
| .El | |
| diff --git a/stddev.c b/stddev.c | |
| t@@ -4,44 +4,50 @@ | |
| #include <unistd.h> | |
| #include <math.h> | |
| #include <limits.h> | |
| +#include <unistd.h> | |
| -#include "arg.h" | |
| #include "util.h" | |
| -char *argv0; | |
| - | |
| static void | |
| usage(void) | |
| { | |
| - errx(1, "usage: %s [-f fmtstr] [-h] [-u]\n", argv0); | |
| + errx(1, "usage: stddev [-d delimstr] [-n] [-p prec] [-u]"); | |
| } | |
| int | |
| main(int argc, char *argv[]) | |
| { | |
| - int ret; | |
| + int ch, prec = 17, finalnl = 1; | |
| size_t i, j, nf = 0, nr = 0, correction = 1; | |
| double *means = NULL, *stdvals = NULL, **vals = NULL; | |
| - char fmtstr[PATH_MAX] = "%.17g"; | |
| + const char *errstr; | |
| + char *delimstr = "\t"; | |
| 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; | |
| - case 'u': | |
| - correction = 0; | |
| - break; | |
| - default: | |
| - usage(); | |
| - } ARGEND; | |
| + while ((ch = getopt(argc, argv, "d:np:u")) != -1) { | |
| + switch (ch) { | |
| + case 'd': | |
| + delimstr = optarg; | |
| + break; | |
| + case 'n': | |
| + finalnl = 0; | |
| + break; | |
| + case 'p': | |
| + prec = strtonum(optarg, -10, INT_MAX, &errstr); | |
| + if (errstr != NULL) | |
| + errx(1, "bad precision value, %s: %s", errstr,… | |
| + break; | |
| + case 'u': | |
| + correction = 0; | |
| + break; | |
| + default: | |
| + usage(); | |
| + } | |
| + } | |
| + /*argc -= optind;*/ | |
| + /*argv += optind;*/ | |
| nr = fscanmatrix(stdin, &vals, &nf); | |
| t@@ -63,7 +69,9 @@ main(int argc, char *argv[]) | |
| stdvals[i] = sqrt(stdvals[i] / ((double)(nr - correction))); | |
| } | |
| - printfarr(fmtstr, stdvals, nf); | |
| + printfarr(delimstr, prec, stdvals, nf); | |
| + if (finalnl) | |
| + putchar('\n'); | |
| free(means); | |
| free(stdvals); | |
| diff --git a/stdvar.1 b/stdvar.1 | |
| t@@ -6,8 +6,9 @@ | |
| .Nd returns the standard variance for each input column | |
| .Sh SYNOPSIS | |
| .Nm | |
| -.Op Fl f Ar fmtstr | |
| -.Op Fl h | |
| +.Op Fl d Ar delimstr | |
| +.Op Fl n | |
| +.Op Fl p Ar prec | |
| .Op Fl u | |
| .Sh DESCRIPTION | |
| .Nm | |
| t@@ -19,18 +20,20 @@ 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 d Ar delimstr | |
| +Separate output values by | |
| +.Ar delimstr . | |
| +The default delimiter is tab characters. | |
| +.It Fl n | |
| +Do not print a newline after the final value. | |
| +.It Fl p prec | |
| +Print the output values with | |
| +.Ar prec | |
| +digits of precision. | |
| +By default, the output is printed with 17 digits of precision, which is | |
| +full double precision on 64-bit systems. | |
| .It Fl u | |
| -Return the uncorrected sample standard variance instead. | |
| +Return the uncorrected sample standard deviation instead. | |
| .El | |
| .Sh EXAMPLES | |
| Compute the corrected standard variance for some input numbers: | |
| diff --git a/stdvar.c b/stdvar.c | |
| t@@ -4,44 +4,50 @@ | |
| #include <unistd.h> | |
| #include <math.h> | |
| #include <limits.h> | |
| +#include <unistd.h> | |
| -#include "arg.h" | |
| #include "util.h" | |
| -char *argv0; | |
| - | |
| static void | |
| usage(void) | |
| { | |
| - errx(1, "usage: %s [-f fmtstr] [-h] [-u]\n", argv0); | |
| + errx(1, "usage: stdvar [-d delimstr] [-n] [-p prec] [-u]"); | |
| } | |
| int | |
| main(int argc, char *argv[]) | |
| { | |
| - int ret; | |
| + int ch, prec = 17, finalnl = 1; | |
| size_t i, j, nf = 0, nr = 0, correction = 1; | |
| double *means = NULL, *stdvars = NULL, **vals = NULL; | |
| - char fmtstr[PATH_MAX] = "%.17g"; | |
| + const char *errstr; | |
| + char *delimstr = "\t"; | |
| 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; | |
| - case 'u': | |
| - correction = 0; | |
| - break; | |
| - default: | |
| - usage(); | |
| - } ARGEND; | |
| + while ((ch = getopt(argc, argv, "d:np:u")) != -1) { | |
| + switch (ch) { | |
| + case 'd': | |
| + delimstr = optarg; | |
| + break; | |
| + case 'n': | |
| + finalnl = 0; | |
| + break; | |
| + case 'p': | |
| + prec = strtonum(optarg, -10, INT_MAX, &errstr); | |
| + if (errstr != NULL) | |
| + errx(1, "bad precision value, %s: %s", errstr,… | |
| + break; | |
| + case 'u': | |
| + correction = 0; | |
| + break; | |
| + default: | |
| + usage(); | |
| + } | |
| + } | |
| + /*argc -= optind;*/ | |
| + /*argv += optind;*/ | |
| nr = fscanmatrix(stdin, &vals, &nf); | |
| t@@ -63,7 +69,9 @@ main(int argc, char *argv[]) | |
| stdvars[i] /= (double)(nr - correction); | |
| } | |
| - printfarr(fmtstr, stdvars, nf); | |
| + printfarr(delimstr, prec, stdvars, nf); | |
| + if (finalnl) | |
| + putchar('\n'); | |
| free(means); | |
| free(stdvars); | |
| diff --git a/sum.1 b/sum.1 | |
| t@@ -6,8 +6,9 @@ | |
| .Nd returns the sum for each column | |
| .Sh SYNOPSIS | |
| .Nm | |
| -.Op Fl f Ar fmtstr | |
| -.Op Fl h | |
| +.Op Fl d Ar delimstr | |
| +.Op Fl n | |
| +.Op Fl p Ar prec | |
| .Sh DESCRIPTION | |
| .Nm | |
| returns the numerical sum for each column in standard input. | |
| t@@ -16,20 +17,22 @@ 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. | |
| +.It Fl d Ar delimstr | |
| +Separate output values by | |
| +.Ar delimstr . | |
| +The default delimiter is tab characters. | |
| +.It Fl n | |
| +Do not print a newline after the final value. | |
| +.It Fl p prec | |
| +Print the output values with | |
| +.Ar prec | |
| +digits of precision. | |
| +By default, the output is printed with 17 digits of precision, which is | |
| +full double precision on 64-bit systems. | |
| .El | |
| .Sh EXAMPLES | |
| .Dl $ printf '1\et2\et3\en4\et5\et6\en' | sum | |
| -.Dl 5 7 9 | |
| +.Dl 5 7 9 | |
| .Sh SEE ALSO | |
| .Xr max 1 , | |
| .Xr mean 1 , | |
| diff --git a/sum.c b/sum.c | |
| t@@ -4,40 +4,45 @@ | |
| #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); | |
| + errx(1, "usage: sum [-d delimstr] [-n] [-p prec]"); | |
| } | |
| int | |
| main(int argc, char *argv[]) | |
| { | |
| - int ret; | |
| + int ch, prec = 17, finalnl = 1; | |
| size_t i = 0, nf = 0, nr = 0, linesize = 0; | |
| - char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g"; | |
| + char *line = NULL, *data = NULL, *delimstr = "\t"; | |
| + const char *errstr; | |
| 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; | |
| + while ((ch = getopt(argc, argv, "d:np:")) != -1) { | |
| + switch (ch) { | |
| + case 'd': | |
| + delimstr = optarg; | |
| + break; | |
| + case 'n': | |
| + finalnl = 0; | |
| + break; | |
| + case 'p': | |
| + prec = strtonum(optarg, 0, INT_MAX, &errstr); | |
| + if (errstr != NULL) | |
| + errx(1, "bad precision value, %s: %s", errstr,… | |
| + break; | |
| + default: | |
| + usage(); | |
| + } | |
| + } | |
| + argc -= optind; | |
| + /*argv += optind;*/ | |
| if (argc > 0) | |
| usage(); | |
| t@@ -55,7 +60,9 @@ main(int argc, char *argv[]) | |
| } | |
| nr++; | |
| } | |
| - printfarr(fmtstr, vals, nf); | |
| + printfarr(delimstr, prec, vals, nf); | |
| + if (finalnl) | |
| + putchar('\n'); | |
| free(line); | |
| free(vals); | |
| diff --git a/transpose.1 b/transpose.1 | |
| t@@ -16,9 +16,9 @@ Input fields must be tab-separated and each line must contai… | |
| same number of fields. | |
| .Sh EXAMPLES | |
| .Dl $ printf '1\et2\et3\en4\et5\et6\en' | transpose | |
| -.Dl 1 4 | |
| -.Dl 2 5 | |
| -.Dl 3 6 | |
| +.Dl 1 4 | |
| +.Dl 2 5 | |
| +.Dl 3 6 | |
| .Sh SEE ALSO | |
| .Xr max 1 , | |
| .Xr mean 1 , | |
| diff --git a/util.c b/util.c | |
| t@@ -45,16 +45,15 @@ printarr(double *arr, size_t len) | |
| } | |
| void | |
| -printfarr(char *fmtstr, double *arr, size_t len) | |
| +printfarr(char *delimstr, int prec, double *arr, size_t len) | |
| { | |
| size_t i; | |
| for (i = 0; i < len; i++) { | |
| - printf(fmtstr, arr[i]); | |
| - if (i < len) | |
| - printf(DELIMSTR); | |
| + printf("%.*g", prec, arr[i]); | |
| + if (i < len - 1) | |
| + fputs(delimstr, stdout); | |
| } | |
| - putchar('\n'); | |
| } | |
| size_t | |
| diff --git a/util.h b/util.h | |
| t@@ -26,7 +26,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); | |
| +void printfarr(char *delimstr, int prec, double *arr, size_t len); | |
| size_t fscanmatrix(FILE *stream, double ***arr, size_t *nf); | |
| #endif |