1pub(crate) fn fround(value: f64) -> f64 {
11 value as f32 as f64
12}
13
14#[derive(Copy, Clone, Debug, PartialEq)]
16pub struct Range {
17 pub min: f64,
18 pub max: f64,
19}
20
21impl Range {
22 pub const UNKNOWN: Range = Range { min: f64::NEG_INFINITY, max: f64::INFINITY };
23
24 pub fn new(min: f64, max: f64) -> Range {
25 Range { min, max }
26 }
27
28 pub fn is_finite(&self) -> bool {
29 self.min.is_finite() && self.max.is_finite()
30 }
31}
32
33pub(crate) const EXACT_GRID_STEPS: f64 = 16_777_216.0;
36pub(crate) fn smallest_grid() -> f64 {
37 pow2(-149)
38}
39pub(crate) fn largest_grid() -> f64 {
40 pow2(127)
41}
42
43pub(crate) fn pow2(exponent: i32) -> f64 {
46 if exponent > 1023 {
47 f64::INFINITY
48 } else if exponent >= -1022 {
49 f64::from_bits(((exponent + 1023) as u64) << 52)
50 } else if exponent >= -1074 {
51 f64::from_bits(1u64 << (exponent + 1074))
52 } else {
53 0.0
54 }
55}
56
57pub(crate) fn lowest_power_of_two(value: f64) -> f64 {
60 debug_assert!(value.is_finite() && value != 0.0);
61 let bits = value.to_bits();
62 let biased_exponent = ((bits >> 52) & 0x7ff) as i32;
63 let fraction = bits & ((1u64 << 52) - 1);
64 if biased_exponent == 0 {
65 pow2(-1074 + fraction.trailing_zeros() as i32)
66 } else {
67 let significand = fraction | (1u64 << 52);
68 pow2(biased_exponent - 1075 + significand.trailing_zeros() as i32)
69 }
70}
71
72pub(crate) fn is_power_of_two_grid(step: f64) -> bool {
73 step.is_finite() && step >= smallest_grid() && step <= largest_grid() && lowest_power_of_two(step) == step
74}
75
76pub(crate) fn power_of_two_exponent_at_least(value: f64) -> i32 {
78 let mut exponent = value.log2().ceil() as i32;
79 while pow2(exponent) < value {
80 exponent += 1;
81 }
82 while pow2(exponent - 1) >= value {
83 exponent -= 1;
84 }
85 exponent
86}
87
88pub(crate) fn relu32(value: f32) -> f32 {
90 if value > 0.0 {
91 value
92 } else if value.is_nan() {
93 f32::NAN
94 } else {
95 0.0
96 }
97}
98
99pub(crate) fn evaluate_boolean(score: f32) -> f32 {
102 const BASE: f32 = 8_388_609.0;
103 (score + BASE) - BASE
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn lowest_power_of_two_matches_handwired() {
112 assert_eq!(lowest_power_of_two(12.0), 4.0);
113 assert_eq!(lowest_power_of_two(0.75), 0.25);
114 assert_eq!(lowest_power_of_two(-3.0), 1.0);
115 assert_eq!(lowest_power_of_two(pow2(-149)), pow2(-149));
116 assert_eq!(lowest_power_of_two(f64::from_bits(6)), pow2(-1073));
117 }
118
119 #[test]
120 fn boolean_atom_rounds_at_one_half() {
121 assert_eq!(evaluate_boolean(0.5), 1.0);
122 assert_eq!(evaluate_boolean(0.5 - 2f32.powi(-25)), 0.0);
123 assert_eq!(evaluate_boolean(0.0), 0.0);
124 assert_eq!(evaluate_boolean(1.0), 1.0);
125 }
126
127 #[test]
128 fn exponent_at_least() {
129 assert_eq!(power_of_two_exponent_at_least(16_384.0), 14);
130 assert_eq!(power_of_two_exponent_at_least(16_385.0), 15);
131 assert_eq!(power_of_two_exponent_at_least(pow2(-149)), -149);
132 }
133}