Skip to content

Commit 829bfc3

Browse files
authored
Merge pull request #4167 from RalfJung/apply_random_float_error
clarify apply_random_float_error logic
2 parents 7ad8dba + 883ba24 commit 829bfc3

File tree

1 file changed

+12
-4
lines changed

1 file changed

+12
-4
lines changed

Diff for: src/tools/miri/src/math.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,26 @@ use rand::distributions::Distribution as _;
33
use rustc_apfloat::Float as _;
44
use rustc_apfloat::ieee::IeeeFloat;
55

6-
/// Disturbes a floating-point result by a relative error on the order of (-2^scale, 2^scale).
6+
/// Disturbes a floating-point result by a relative error in the range (-2^scale, 2^scale).
7+
///
8+
/// For a 2^N ULP error, you can use an `err_scale` of `-(F::PRECISION - 1 - N)`.
9+
/// In other words, a 1 ULP (absolute) error is the same as a `2^-(F::PRECISION-1)` relative error.
10+
/// (Subtracting 1 compensates for the integer bit.)
711
pub(crate) fn apply_random_float_error<F: rustc_apfloat::Float>(
812
ecx: &mut crate::MiriInterpCx<'_>,
913
val: F,
1014
err_scale: i32,
1115
) -> F {
1216
let rng = ecx.machine.rng.get_mut();
1317
// Generate a random integer in the range [0, 2^PREC).
18+
// (When read as binary, the position of the first `1` determines the exponent,
19+
// and the remaining bits fill the mantissa. `PREC` is one plus the size of the mantissa,
20+
// so this all works out.)
1421
let dist = rand::distributions::Uniform::new(0, 1 << F::PRECISION);
15-
let err = F::from_u128(dist.sample(rng))
16-
.value
17-
.scalbn(err_scale.strict_sub(F::PRECISION.try_into().unwrap()));
22+
let r = F::from_u128(dist.sample(rng)).value;
23+
// Multiply this with 2^(scale - PREC). The result is between 0 and
24+
// 2^PREC * 2^(scale - PREC) = 2^scale.
25+
let err = r.scalbn(err_scale.strict_sub(F::PRECISION.try_into().unwrap()));
1826
// give it a random sign
1927
let err = if rng.gen::<bool>() { -err } else { err };
2028
// multiple the value with (1+err)

0 commit comments

Comments
 (0)