1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use core::mem::transmute;
use super::float_info::FloatInfo;
pub trait LoadExp<Exponent> {
type Output;
/// Returns multiplication of a number by a power of 2 with given exponent.
/// ```
/// use traiter::numbers::LoadExp;
/// // floating point numbers
/// assert_eq!(LoadExp::load_exp(0.5_f32, -1i32), 0.25_f32);
/// assert_eq!(LoadExp::load_exp(0.5_f32, 0i32), 0.5_f32);
/// assert_eq!(LoadExp::load_exp(0.5_f32, 1i32), 1.0_f32);
/// ```
fn load_exp(self, exponent: Exponent) -> Self::Output;
}
macro_rules! float_load_exp_impl {
($float:ty, $bits:ty) => {
impl LoadExp<i32> for $float {
type Output = Self;
#[inline]
fn load_exp(mut self, mut exponent: i32) -> Self::Output {
const EXPONENT_BASE: $bits =
(1 << (<$float>::EXPONENT_BITS_COUNT - 1usize)) - 1;
const EXPONENT_LOWER_BOUND: i32 = <$float>::MIN_EXP - 1;
const EXPONENT_UPPER_BOUND: i32 = <$float>::MAX_EXP - 1;
if exponent > EXPONENT_UPPER_BOUND {
const SCALE: $float = unsafe {
transmute::<$bits, $float>(
(((EXPONENT_BASE as i32) + EXPONENT_UPPER_BOUND)
as $bits)
<< <$float>::SIGNIFICAND_BITS_COUNT,
)
};
self *= SCALE;
exponent -= EXPONENT_UPPER_BOUND;
if exponent > EXPONENT_UPPER_BOUND {
self *= SCALE;
exponent -= EXPONENT_UPPER_BOUND;
if exponent > EXPONENT_UPPER_BOUND {
exponent = EXPONENT_UPPER_BOUND;
}
}
} else if exponent < EXPONENT_LOWER_BOUND {
const NON_EXPONENT_BITS_COUNT: usize =
<$float>::SIGN_BITS_COUNT
+ <$float>::SIGNIFICAND_BITS_COUNT;
const FIRST_MULTIPLIER: $float = unsafe {
transmute::<$bits, $float>(
(EXPONENT_BASE
+ (NON_EXPONENT_BITS_COUNT as $bits))
<< <$float>::SIGNIFICAND_BITS_COUNT,
)
};
const SECOND_MULTIPLIER: $float = unsafe {
transmute::<$bits, $float>(
(((EXPONENT_BASE as i32) + EXPONENT_LOWER_BOUND)
as $bits)
<< <$float>::SIGNIFICAND_BITS_COUNT,
)
};
const SCALE: $float = FIRST_MULTIPLIER * SECOND_MULTIPLIER;
const EXPONENT_DECREMENT: i32 = (NON_EXPONENT_BITS_COUNT
as i32)
+ EXPONENT_LOWER_BOUND;
self *= SCALE;
exponent -= EXPONENT_DECREMENT;
if exponent < EXPONENT_LOWER_BOUND {
self *= SCALE;
exponent -= EXPONENT_DECREMENT;
if exponent < EXPONENT_LOWER_BOUND {
exponent = EXPONENT_LOWER_BOUND;
}
}
}
self * Self::from_bits(
(((EXPONENT_BASE as i32) + exponent) as $bits)
<< <$float>::SIGNIFICAND_BITS_COUNT,
)
}
}
};
}
float_load_exp_impl!(f32, u32);
float_load_exp_impl!(f64, u64);