trandnum(1): use getopt(2) and safe formatting specs - numtools - perform numer… | |
git clone git://src.adamsgaard.dk/numtools | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 258495d0a32a728ba75d8569df12b7989d731646 | |
parent 76946865659abbf6fb22ab476a2c6075aed14a99 | |
Author: Anders Damsgaard <[email protected]> | |
Date: Wed, 11 May 2022 11:58:44 +0200 | |
randnum(1): use getopt(2) and safe formatting specs | |
Diffstat: | |
M randnum.1 | 43 +++++++++++++++--------------… | |
M randnum.c | 78 +++++++++++++++++++----------… | |
2 files changed, 68 insertions(+), 53 deletions(-) | |
--- | |
diff --git a/randnum.1 b/randnum.1 | |
t@@ -6,9 +6,10 @@ | |
.Nd produces random numbers in a range | |
.Sh SYNOPSIS | |
.Nm | |
-.Op Fl f Ar fmtstr | |
-.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 s Ar seed | |
.Oo | |
.Op Ar min_val | |
t@@ -40,19 +41,20 @@ within the same microsecond will produce the same result. | |
.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. | |
-.It Fl n Ar num | |
+.It Fl d Ar delimstr | |
+Separate output values by | |
+.Ar delimstr . | |
+The default delimiter is newlines. | |
+.It Fl n | |
+Do not print a newline after the final value. | |
+.It Fl N num | |
Number of random points to generate. | |
-The default is 1. | |
+.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 Ar seed | |
Seed the pseudo-random number generator with this value, which is used | |
to generate reproducable binning. | |
t@@ -63,13 +65,10 @@ Due to the randomness, your output may differ: | |
.Dl $ randnum | |
.Dl 0.38385568287140259 | |
.Pp | |
-Generate five points in the range [-10;10[ and print with three significant di… | |
-.Dl $ randnum -n 5 -f '%.3g' -- -10 10 | |
-.Dl -4.16 | |
-.Dl -3.36 | |
-.Dl -5.8 | |
-.Dl -2.31 | |
-.Dl 4.4 | |
+Generate five points in the range [-10;10[ and print with three | |
+significant digits seperated by spaces: | |
+.Dl $ randnum -N 5 -p 3 -d ' ' -- -10 10 | |
+.Dl -5.52 -5.5 -3.88 3.49 -3.11 | |
.Sh SEE ALSO | |
.Xr randcounts 1 , | |
.Xr range 1 , | |
diff --git a/randnum.c b/randnum.c | |
t@@ -4,59 +4,72 @@ | |
#include <limits.h> | |
#include <string.h> | |
#include <math.h> | |
+#include <unistd.h> | |
#include <sys/time.h> | |
-#include "arg.h" | |
#include "util.h" | |
-char *argv0; | |
- | |
static void | |
usage(void) | |
{ | |
- errx(1, "usage: %s [-f fmtstr] [-h] [-n num] [-s seed] " | |
- "[[min_val] max_val]\n", argv0); | |
+ errx(1, "usage: randnum [-d delimstr] [-n] [-N num] " | |
+ "[-p prec] [-s seed] " | |
+ "[[min_val] max_val]\n"); | |
} | |
int | |
main(int argc, char *argv[]) | |
{ | |
- int i, ret, s = 0; | |
+ int i, ret, ch, s = 0, prec = 17, finalnl = 1; | |
long j, seed, n = 1; | |
double val, minv = 0.0, maxv = 1.0; | |
- char fmtstr[PATH_MAX] = "%.17g"; | |
+ char *delimstr = "\n"; | |
+ const char *errstr; | |
struct timeval t1; | |
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 'n': | |
- n = atoi(EARGF(usage())); | |
- break; | |
- case 's': | |
- s = 1; | |
- seed = atol(EARGF(usage())); | |
- break; | |
- default: | |
- usage(); | |
- } ARGEND; | |
+ while ((ch = getopt(argc, argv, "d:nN:p: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 'p': | |
+ prec = strtonum(optarg, -10, 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 > 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]); | |
if (s) | |
#ifdef __OpenBSD__ | |
t@@ -70,9 +83,12 @@ main(int argc, char *argv[]) | |
#endif | |
for (i = 0; i < n; i++) { | |
- printf(fmtstr, drand48() * (maxv - minv) + minv); | |
- putchar('\n'); | |
+ printf("%.*g", prec, drand48() * (maxv - minv) + minv); | |
+ if (i < n - 1) | |
+ fputs(delimstr, stdout); | |
} | |
+ if (finalnl) | |
+ putchar('\n'); | |
return 0; | |
} |