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++) {

Reply via email to