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 |