Skip to content

Commit ff1ef50

Browse files
Jim LaskeyTheRealMDoerr
authored andcommitted
8273056: java.util.random does not correctly sample exponential or Gaussian distributions
Backport-of: 3d98ec1b7bc77237177ecfc069c0e9a7e75829bc
1 parent e2103de commit ff1ef50

File tree

1 file changed

+11
-9
lines changed

1 file changed

+11
-9
lines changed

src/java.base/share/classes/jdk/internal/util/random/RandomSupport.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,10 +1186,10 @@ public static double computeNextExponential(RandomGenerator rng) {
11861186
// For the exponential distribution, every overhang is convex.
11871187
final double[] X = DoubleZigguratTables.exponentialX;
11881188
final double[] Y = DoubleZigguratTables.exponentialY;
1189-
for (;; U1 = (rng.nextLong() >>> 1)) {
1189+
// At this point, the high-order bits of U1 have not been used yet,
1190+
// but we need the value in U1 to be positive.
1191+
for (U1 = (U1 >>> 1);; U1 = (rng.nextLong() >>> 1)) {
11901192
long U2 = (rng.nextLong() >>> 1);
1191-
// Compute the actual x-coordinate of the randomly chosen point.
1192-
double x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1);
11931193
// Does the point lie below the curve?
11941194
long Udiff = U2 - U1;
11951195
if (Udiff < 0) {
@@ -1200,11 +1200,13 @@ public static double computeNextExponential(RandomGenerator rng) {
12001200
U2 = U1;
12011201
U1 -= Udiff;
12021202
}
1203+
// Compute the actual x-coordinate of the randomly chosen point.
1204+
double x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1);
12031205
if (Udiff >= DoubleZigguratTables.exponentialConvexMargin) {
12041206
return x + extra; // The chosen point is way below the curve; accept it.
12051207
}
12061208
// Compute the actual y-coordinate of the randomly chosen point.
1207-
double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2);
1209+
double y = (Y[j] * 0x1.0p63) + ((Y[j-1] - Y[j]) * (double)U2);
12081210
// Now see how that y-coordinate compares to the curve
12091211
if (y <= Math.exp(-x)) {
12101212
return x + extra; // The chosen point is below the curve; accept it.
@@ -1323,7 +1325,7 @@ public static double computeNextGaussian(RandomGenerator rng) {
13231325
continue; // The chosen point is way above the curve; reject it.
13241326
}
13251327
// Compute the actual y-coordinate of the randomly chosen point.
1326-
double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2);
1328+
double y = (Y[j] * 0x1.0p63) + ((Y[j-1] - Y[j]) * (double)U2);
13271329
// Now see how that y-coordinate compares to the curve
13281330
if (y <= Math.exp(-0.5*x*x)) {
13291331
break; // The chosen point is below the curve; accept it.
@@ -1348,8 +1350,6 @@ public static double computeNextGaussian(RandomGenerator rng) {
13481350
} else if (j < DoubleZigguratTables.normalInflectionIndex) { // Convex overhang
13491351
for (;; U1 = (rng.nextLong() >>> 1)) {
13501352
long U2 = (rng.nextLong() >>> 1);
1351-
// Compute the actual x-coordinate of the randomly chosen point.
1352-
x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1);
13531353
// Does the point lie below the curve?
13541354
long Udiff = U2 - U1;
13551355
if (Udiff < 0) {
@@ -1360,11 +1360,13 @@ public static double computeNextGaussian(RandomGenerator rng) {
13601360
U2 = U1;
13611361
U1 -= Udiff;
13621362
}
1363+
// Compute the actual x-coordinate of the randomly chosen point.
1364+
x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1);
13631365
if (Udiff >= DoubleZigguratTables.normalConvexMargin) {
13641366
break; // The chosen point is way below the curve; accept it.
13651367
}
13661368
// Compute the actual y-coordinate of the randomly chosen point.
1367-
double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2);
1369+
double y = (Y[j] * 0x1.0p63) + ((Y[j-1] - Y[j]) * (double)U2);
13681370
// Now see how that y-coordinate compares to the curve
13691371
if (y <= Math.exp(-0.5*x*x)) break; // The chosen point is below the curve; accept it.
13701372
// Otherwise, we reject this sample and have to try again.
@@ -1384,7 +1386,7 @@ public static double computeNextGaussian(RandomGenerator rng) {
13841386
continue; // The chosen point is way above the curve; reject it.
13851387
}
13861388
// Compute the actual y-coordinate of the randomly chosen point.
1387-
double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2);
1389+
double y = (Y[j] * 0x1.0p63) + ((Y[j-1] - Y[j]) * (double)U2);
13881390
// Now see how that y-coordinate compares to the curve
13891391
if (y <= Math.exp(-0.5*x*x)) {
13901392
break; // The chosen point is below the curve; accept it.

0 commit comments

Comments
 (0)