|
| 1 | +use super::super::{CastFrom, CastInto, Float, IntTy, MinInt}; |
| 2 | + |
| 3 | +/// Scale the exponent. |
| 4 | +/// |
| 5 | +/// From N3220: |
| 6 | +/// |
| 7 | +/// > The scalbn and scalbln functions compute `x * b^n`, where `b = FLT_RADIX` if the return type |
| 8 | +/// > of the function is a standard floating type, or `b = 10` if the return type of the function |
| 9 | +/// > is a decimal floating type. A range error occurs for some finite x, depending on n. |
| 10 | +/// > |
| 11 | +/// > [...] |
| 12 | +/// > |
| 13 | +/// > * `scalbn(±0, n)` returns `±0`. |
| 14 | +/// > * `scalbn(x, 0)` returns `x`. |
| 15 | +/// > * `scalbn(±∞, n)` returns `±∞`. |
| 16 | +/// > |
| 17 | +/// > If the calculation does not overflow or underflow, the returned value is exact and |
| 18 | +/// > independent of the current rounding direction mode. |
| 19 | +pub fn scalbn<F: Float>(mut x: F, mut n: i32) -> F |
| 20 | +where |
| 21 | + u32: CastInto<F::Int>, |
| 22 | + F::Int: CastFrom<i32>, |
| 23 | + F::Int: CastFrom<u32>, |
| 24 | +{ |
| 25 | + if n == 0 || x == F::ZERO || x.is_nan() || x.is_infinite() { |
| 26 | + return x; |
| 27 | + } |
| 28 | + |
| 29 | + // Bits including the implicit bit |
| 30 | + let sig_total_bits = F::SIG_BITS + 1; |
| 31 | + |
| 32 | + // Maximum and minimum values when biased |
| 33 | + let exp_max: i32 = F::EXP_BIAS as i32; |
| 34 | + let exp_min = -(exp_max - 1); |
| 35 | + let exp_min_with_subnorm = -((F::EXP_BIAS + F::SIG_BITS + 1) as i32); |
| 36 | + |
| 37 | + // let x_exp = x.exp(); |
| 38 | + // let x_sig = x.frac(); |
| 39 | + |
| 40 | + if n > exp_max { |
| 41 | + return F::INFINITY * x.signum(); |
| 42 | + } |
| 43 | + |
| 44 | + if n < exp_min_with_subnorm { |
| 45 | + return F::ZERO * x.signum(); |
| 46 | + } |
| 47 | + |
| 48 | + // 2 ^ Emax, where Emax is the maximum biased exponent value (1023 for f64) |
| 49 | + let f_exp_max = F::from_bits(F::Int::cast_from(F::EXP_BIAS << 1) << F::SIG_BITS); |
| 50 | + // 2 ^ Emin, where Emin is the minimum biased exponent value (-1022 for f64) |
| 51 | + let f_exp_min = F::from_bits(IntTy::<F>::ONE << F::SIG_BITS); |
| 52 | + // 2 ^ sig_total_bits, representation of what can be accounted for with subnormals |
| 53 | + let f_exp_subnorm = F::from_bits((F::EXP_BIAS + sig_total_bits).cast() << F::SIG_BITS); |
| 54 | + |
| 55 | + // std::println!("{exp_max} {exp_min} {n}"); |
| 56 | + // std::dbg!(x, exp_max, exp_min, n); |
| 57 | + |
| 58 | + if n > exp_max { |
| 59 | + x *= f_exp_max; |
| 60 | + n -= exp_max; |
| 61 | + // std::dbg!(11, x, n); |
| 62 | + if n > exp_max { |
| 63 | + x *= f_exp_max; |
| 64 | + n -= exp_max; |
| 65 | + // std::dbg!(12, x, n); |
| 66 | + if n > exp_max { |
| 67 | + n = exp_max; |
| 68 | + // std::dbg!(13, x, n); |
| 69 | + } |
| 70 | + } |
| 71 | + } else if n < exp_min { |
| 72 | + let mul = f_exp_min * f_exp_subnorm; |
| 73 | + let add = (exp_max - 1) - sig_total_bits as i32; |
| 74 | + |
| 75 | + x *= mul; |
| 76 | + n += add; |
| 77 | + // std::dbg!(21, x, n); |
| 78 | + if n < exp_min { |
| 79 | + x *= mul; |
| 80 | + n += add; |
| 81 | + // std::dbg!(22, x, n); |
| 82 | + if n < exp_min { |
| 83 | + n = exp_min; |
| 84 | + // std::dbg!(23, x, n); |
| 85 | + } |
| 86 | + } |
| 87 | + } |
| 88 | + |
| 89 | + x * F::from_bits(F::Int::cast_from(F::EXP_BIAS as i32 + n) << F::SIG_BITS) |
| 90 | +} |
| 91 | + |
| 92 | +// DELETE |
| 93 | + |
| 94 | +extern crate std; |
| 95 | + |
| 96 | +#[test] |
| 97 | +fn testme() { |
| 98 | + assert_eq!(scalbn::<f16>(f16::from_bits(0x6ecb), -1336428830), f16::ZERO); |
| 99 | +} |
| 100 | + |
| 101 | +#[test] |
| 102 | +fn testme2() { |
| 103 | + // assert_eq!(scalbn(-f64::INFINITY, -2147033648), f64::ZERO); |
| 104 | +} |
0 commit comments