From c15edb9d96dd6a4461bd687f8dc8ad5388b02f02 Mon Sep 17 00:00:00 2001 From: dds Date: Mon, 6 Nov 2006 13:55:11 +0000 Subject: [PATCH] Do What I Mean when the user asks for random integers or characters. Up to now jot would fail to generate the last character in the range or skew the integer distribution in a way that would generate the numbers in the range's limits with half the probability of the rest. This modification fixes the program, rather than documenting the strange behavior, as suggested in docs/54879. Also, correctly specify the range of random(3). PR: docs/54879 MFC after: 2 weeks --- usr.bin/jot/jot.1 | 19 ++++++++++++++++++- usr.bin/jot/jot.c | 39 ++++++++++++++++++++++++++++++++------- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/usr.bin/jot/jot.1 b/usr.bin/jot/jot.1 index e1e98acbb2ac..1aa0d623bb32 100644 --- a/usr.bin/jot/jot.1 +++ b/usr.bin/jot/jot.1 @@ -32,7 +32,7 @@ .\" @(#)jot.1 8.1 (Berkeley) 6/6/93 .\" $FreeBSD$ .\" -.Dd June 6, 1993 +.Dd November 6, 2006 .Dt JOT 1 .Os .Sh NAME @@ -145,6 +145,23 @@ when no seed is specified, and through .Xr random 3 when a seed is given. +When +.Nm +is asked to generate random integers or characters with begin +and end values in the range of the random number generator function +and no format is specified with one of the +.Fl w , +.Fl b , +or +.Fl p +options, +.Nm +will arrange for all the values in the range to appear in the output +with an equal probability. +In all other cases be careful to ensure that the output format's +rounding or truncation will not skew the distribution of output +values in an unintended way. +.Pp The name .Nm derives in part from diff --git a/usr.bin/jot/jot.c b/usr.bin/jot/jot.c index 1464e4d9e583..d7f700c2c2e5 100644 --- a/usr.bin/jot/jot.c +++ b/usr.bin/jot/jot.c @@ -103,7 +103,9 @@ main(int argc, char **argv) unsigned int mask = 0; int n = 0; int ch; - bool have_seed = false; + bool use_random = false; + bool have_format = false; + double divisor; while ((ch = getopt(argc, argv, "rb:w:cs:np:")) != -1) switch (ch) { @@ -123,6 +125,7 @@ main(int argc, char **argv) if (strlcpy(format, optarg, sizeof(format)) >= sizeof(format)) errx(1, "-%c word too long", ch); + have_format = true; break; case 's': sepstring = optarg; @@ -131,6 +134,7 @@ main(int argc, char **argv) prec = atoi(optarg); if (prec <= 0) errx(1, "bad precision value"); + have_format = true; break; default: usage(); @@ -145,7 +149,7 @@ main(int argc, char **argv) errx(1, "bad s value: %s", argv[3]); mask |= HAVE_STEP; if (randomize) - have_seed = true; + use_random = true; } /* FALLTHROUGH */ case 3: @@ -258,14 +262,35 @@ main(int argc, char **argv) if (reps == 0) infinity = 1; if (randomize) { - x = (ender - begin) * (ender > begin ? 1 : -1); - if (have_seed) + if (use_random) { srandom((unsigned long)s); + divisor = (double)INT32_MAX + 1; + } else + divisor = (double)UINT32_MAX + 1; + + /* + * Attempt to DWIM when the user has specified an + * integer range within that of the random number + * generator: distribute the numbers equally in + * the range [begin .. ender]. Jot's default %.0f + * format would make the appearance of the first and + * last specified value half as likely as the rest. + */ + if (!have_format && prec == 0 && + begin >= 0 && begin < divisor && + ender >= 0 && ender < divisor) { + ender += 1; + nosign = 1; + intdata = 1; + (void)strlcpy(format, + chardata ? "%c" : "%u", sizeof(format)); + } + x = (ender - begin) * (ender > begin ? 1 : -1); for (i = 1; i <= reps || infinity; i++) { - if (have_seed) - y = random() / ((double)LONG_MAX + 1); + if (use_random) + y = random() / divisor; else - y = arc4random() / ((double)UINT32_MAX + 1); + y = arc4random() / divisor; if (putdata(y * x + begin, reps - i)) errx(1, "range error in conversion"); }