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
This commit is contained in:
dds 2006-11-06 13:55:11 +00:00
parent 13dc4f1b11
commit c15edb9d96
2 changed files with 50 additions and 8 deletions

View File

@ -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

View File

@ -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");
}