authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-13 16:50:18-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-05-13 16:50:18-04:00
logf32928c50dabde1dee40b7137beef0fe72e89b49
tree9ce6911652a2044c1efc6951bd9519d194789cab
parent24633b561369b5847e33d54ac02b77f23c9f8519
parent23ef7a80601d553bc9cce24500c9d079883867a4
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11641 from erikarvstedt/fixup_rand_float_improvement

Minor fixes for random float generation

2 files changed, 14 insertions(+), 11 deletions(-)

lib/std/rand.zig+11-8
...@@ -247,19 +247,21 @@ pub const Random = struct {...@@ -247,19 +247,21 @@ pub const Random = struct {
247247
248 /// Return a floating point value evenly distributed in the range [0, 1).248 /// Return a floating point value evenly distributed in the range [0, 1).
249 pub fn float(r: Random, comptime T: type) T {249 pub fn float(r: Random, comptime T: type) T {
250 // Generate a uniformly random value between for the mantissa.250 // Generate a uniformly random value for the mantissa.
251 // Then generate an exponentially biased random value for the exponent.251 // Then generate an exponentially biased random value for the exponent.
252 // Over the previous method, this has the advantage of being able to252 // This covers every possible value in the range.
253 // represent every possible value in the available range.
254 switch (T) {253 switch (T) {
255 f32 => {254 f32 => {
256 // Use 23 random bits for the mantissa, and the rest for the exponent.255 // Use 23 random bits for the mantissa, and the rest for the exponent.
257 // If all 41 bits are zero, generate additional random bits, until a256 // If all 41 bits are zero, generate additional random bits, until a
258 // set bit is found, or 126 bits have been generated.257 // set bit is found, or 126 bits have been generated.
259 const rand = r.int(u64);258 const rand = r.int(u64);
260 var rand_lz = @clz(u64, rand | 0x7FFFFF);259 var rand_lz = @clz(u64, rand);
261 if (rand_lz == 41) {260 if (rand_lz >= 41) {
262 rand_lz += @clz(u64, r.int(u64));261 // TODO: when #5177 or #489 is implemented,
262 // tell the compiler it is unlikely (1/2^41) to reach this point.
263 // (Same for the if branch and the f64 calculations below.)
264 rand_lz = 41 + @clz(u64, r.int(u64));
263 if (rand_lz == 41 + 64) {265 if (rand_lz == 41 + 64) {
264 // It is astronomically unlikely to reach this point.266 // It is astronomically unlikely to reach this point.
265 rand_lz += @clz(u32, r.int(u32) | 0x7FF);267 rand_lz += @clz(u32, r.int(u32) | 0x7FF);
...@@ -274,8 +276,9 @@ pub const Random = struct {...@@ -274,8 +276,9 @@ pub const Random = struct {
274 // If all 12 bits are zero, generate additional random bits, until a276 // If all 12 bits are zero, generate additional random bits, until a
275 // set bit is found, or 1022 bits have been generated.277 // set bit is found, or 1022 bits have been generated.
276 const rand = r.int(u64);278 const rand = r.int(u64);
277 var rand_lz: u64 = @clz(u64, rand | 0xFFFFFFFFFFFFF);279 var rand_lz: u64 = @clz(u64, rand);
278 if (rand_lz == 12) {280 if (rand_lz >= 12) {
281 rand_lz = 12;
279 while (true) {282 while (true) {
280 // It is astronomically unlikely for this loop to execute more than once.283 // It is astronomically unlikely for this loop to execute more than once.
281 const addl_rand_lz = @clz(u64, r.int(u64));284 const addl_rand_lz = @clz(u64, r.int(u64));
lib/std/rand/test.zig+3-3
...@@ -336,13 +336,13 @@ test "Random float chi-square goodness of fit" {...@@ -336,13 +336,13 @@ test "Random float chi-square goodness of fit" {
336 if (f32_put.found_existing) {336 if (f32_put.found_existing) {
337 f32_put.value_ptr.* += 1;337 f32_put.value_ptr.* += 1;
338 } else {338 } else {
339 f32_put.value_ptr.* = 0;339 f32_put.value_ptr.* = 1;
340 }340 }
341 var f64_put = try f64_hist.getOrPut(@floatToInt(u32, rand_f64 * @intToFloat(f64, num_buckets)));341 var f64_put = try f64_hist.getOrPut(@floatToInt(u32, rand_f64 * @intToFloat(f64, num_buckets)));
342 if (f64_put.found_existing) {342 if (f64_put.found_existing) {
343 f64_put.value_ptr.* += 1;343 f64_put.value_ptr.* += 1;
344 } else {344 } else {
345 f64_put.value_ptr.* = 0;345 f64_put.value_ptr.* = 1;
346 }346 }
347 }347 }
348348
...@@ -371,7 +371,7 @@ test "Random float chi-square goodness of fit" {...@@ -371,7 +371,7 @@ test "Random float chi-square goodness of fit" {
371 }371 }
372 }372 }
373373
374 // Corresponds to a p-value > 0.05.374 // Accept p-values >= 0.05.
375 // Critical value is calculated by opening a Python interpreter and running:375 // Critical value is calculated by opening a Python interpreter and running:
376 // scipy.stats.chi2.isf(0.05, num_buckets - 1)376 // scipy.stats.chi2.isf(0.05, num_buckets - 1)
377 const critical_value = 1073.6426506574246;377 const critical_value = 1073.6426506574246;