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:
parent
13dc4f1b11
commit
c15edb9d96
@ -32,7 +32,7 @@
|
|||||||
.\" @(#)jot.1 8.1 (Berkeley) 6/6/93
|
.\" @(#)jot.1 8.1 (Berkeley) 6/6/93
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd June 6, 1993
|
.Dd November 6, 2006
|
||||||
.Dt JOT 1
|
.Dt JOT 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -145,6 +145,23 @@ when no seed is specified,
|
|||||||
and through
|
and through
|
||||||
.Xr random 3
|
.Xr random 3
|
||||||
when a seed is given.
|
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
|
The name
|
||||||
.Nm
|
.Nm
|
||||||
derives in part from
|
derives in part from
|
||||||
|
@ -103,7 +103,9 @@ main(int argc, char **argv)
|
|||||||
unsigned int mask = 0;
|
unsigned int mask = 0;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
int ch;
|
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)
|
while ((ch = getopt(argc, argv, "rb:w:cs:np:")) != -1)
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
@ -123,6 +125,7 @@ main(int argc, char **argv)
|
|||||||
if (strlcpy(format, optarg, sizeof(format)) >=
|
if (strlcpy(format, optarg, sizeof(format)) >=
|
||||||
sizeof(format))
|
sizeof(format))
|
||||||
errx(1, "-%c word too long", ch);
|
errx(1, "-%c word too long", ch);
|
||||||
|
have_format = true;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
sepstring = optarg;
|
sepstring = optarg;
|
||||||
@ -131,6 +134,7 @@ main(int argc, char **argv)
|
|||||||
prec = atoi(optarg);
|
prec = atoi(optarg);
|
||||||
if (prec <= 0)
|
if (prec <= 0)
|
||||||
errx(1, "bad precision value");
|
errx(1, "bad precision value");
|
||||||
|
have_format = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
@ -145,7 +149,7 @@ main(int argc, char **argv)
|
|||||||
errx(1, "bad s value: %s", argv[3]);
|
errx(1, "bad s value: %s", argv[3]);
|
||||||
mask |= HAVE_STEP;
|
mask |= HAVE_STEP;
|
||||||
if (randomize)
|
if (randomize)
|
||||||
have_seed = true;
|
use_random = true;
|
||||||
}
|
}
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case 3:
|
case 3:
|
||||||
@ -258,14 +262,35 @@ main(int argc, char **argv)
|
|||||||
if (reps == 0)
|
if (reps == 0)
|
||||||
infinity = 1;
|
infinity = 1;
|
||||||
if (randomize) {
|
if (randomize) {
|
||||||
x = (ender - begin) * (ender > begin ? 1 : -1);
|
if (use_random) {
|
||||||
if (have_seed)
|
|
||||||
srandom((unsigned long)s);
|
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++) {
|
for (i = 1; i <= reps || infinity; i++) {
|
||||||
if (have_seed)
|
if (use_random)
|
||||||
y = random() / ((double)LONG_MAX + 1);
|
y = random() / divisor;
|
||||||
else
|
else
|
||||||
y = arc4random() / ((double)UINT32_MAX + 1);
|
y = arc4random() / divisor;
|
||||||
if (putdata(y * x + begin, reps - i))
|
if (putdata(y * x + begin, reps - i))
|
||||||
errx(1, "range error in conversion");
|
errx(1, "range error in conversion");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user