This is the second poposal:
In addition to fixing the bug Otto noticed, restore the previous
behavior when -r is used in combination with -w or -c. This is done by
checking whether those flag were specified on the command line.
In particular, we have the following situation:
$ obj/jot -r 100000 1 3 | sort -n | uniq -c
33689 1
33171 2
33140 3
$ obj/jot -w %d -r 100000 1 3 | sort -n | uniq -c
50043 1
49957 2
The man page bits of this patch are supposed to exhibit this behavior
more clearly.
This matches the behavior of FreeBSD and OS X, but not Linux and NetBSD.
Index: jot.1
===================================================================
RCS file: /var/cvs/src/usr.bin/jot/jot.1,v
retrieving revision 1.19
diff -u -p -r1.19 jot.1
--- jot.1 4 Jan 2016 23:21:28 -0000 1.19
+++ jot.1 16 Jul 2016 19:08:50 -0000
@@ -227,23 +227,13 @@ $ jot -w %d 6 1 10 0.5
.Ed
.Pp
For random sequences, the output format also influences the range
-and distribution of the generated numbers:
+of the generated numbers:
.Bd -literal -offset indent
-$ jot -r 100000 1 3 | sort -n | uniq -c
-24950 1
-50038 2
-25012 3
-.Ed
-.Pp
-The values at the beginning and end of the interval
-are generated less frequently than the other values.
-There are several ways to solve this problem and generate evenly distributed
-integers:
-.Bd -literal -offset indent
-$ jot -r -p 0 100000 0.5 3.5 | sort -n | uniq -c
-33374 1
-33363 2
-33263 3
+$ jot -r 100000 1 4 | sort -n | uniq -c
+25114 1
+24953 2
+24919 3
+25014 4
$ jot -w %d -r 100000 1 4 | sort -n | uniq -c
33306 1
Index: jot.c
===================================================================
RCS file: /var/cvs/src/usr.bin/jot/jot.c,v
retrieving revision 1.27
diff -u -p -r1.27 jot.c
--- jot.c 10 Jan 2016 01:15:52 -0000 1.27
+++ jot.c 16 Jul 2016 19:06:55 -0000
@@ -85,6 +85,7 @@ main(int argc, char *argv[])
int n = 0;
int ch;
const char *errstr;
+ bool wflag = false;
if (pledge("stdio", NULL) == -1)
err(1, "pledge");
@@ -95,6 +96,7 @@ main(int argc, char *argv[])
randomize = true;
break;
case 'c':
+ wflag = true;
chardata = true;
break;
case 'n':
@@ -107,6 +109,7 @@ main(int argc, char *argv[])
errx(1, "-b word too long");
break;
case 'w':
+ wflag = true;
if (strlcpy(format, optarg, sizeof(format)) >=
sizeof(format))
errx(1, "-w word too long");
@@ -277,9 +280,6 @@ main(int argc, char *argv[])
if (prec > 9) /* pow(10, prec) > UINT32_MAX */
errx(1, "requested precision too large");
- while (prec-- > 0)
- pow10 *= 10;
-
if (ender < begin) {
x = begin;
begin = ender;
@@ -287,16 +287,23 @@ main(int argc, char *argv[])
}
x = ender - begin;
- /*
- * If pow10 * (ender - begin) is an integer, use
- * arc4random_uniform().
- */
- use_unif = fmod(pow10 * (ender - begin), 1) == 0;
- if (use_unif) {
- uintx = pow10 * (ender - begin);
- if (uintx >= UINT32_MAX)
- errx(1, "requested range too large");
- uintx++;
+ if (wflag ||
+ (prec == 0 && (fmod(ender, 1) != 0 || fmod(begin, 1) != 0)))
+ use_unif = 0;
+ else {
+ while (prec-- > 0)
+ pow10 *= 10;
+ /*
+ * If pow10 * (ender - begin) is an integer, use
+ * arc4random_uniform().
+ */
+ use_unif = fmod(pow10 * (ender - begin), 1) == 0;
+ if (use_unif) {
+ uintx = pow10 * (ender - begin);
+ if (uintx >= UINT32_MAX)
+ errx(1, "requested range too large");
+ uintx++;
+ }
}
for (i = 1; i <= reps || infinity; i++) {