1pub const fn roundf_ties_even(x: f32) -> f32 {
31 const BIAS: i32 = 0x7f;
32 const MANT_DIG: i32 = 24;
33 const MAX_EXP: i32 = 2 * BIAS + 1;
34 let mut ix: u32 = x.to_bits();
35 let ux: u32 = ix & 0x7fffffff;
36 let exponent: i32 = (ux >> (MANT_DIG - 1)) as i32;
37 if exponent >= BIAS + MANT_DIG - 1 {
38 if exponent == MAX_EXP {
40 return x + x;
42 } else {
43 return x;
44 }
45 } else if exponent >= BIAS {
46 let int_pos: i32 = (BIAS + MANT_DIG - 1) - exponent;
51 let half_pos: i32 = int_pos - 1;
52 let half_bit: u32 = 1u32 << half_pos;
53 let int_bit: u32 = 1u32 << int_pos;
54 if (ix & (int_bit | (half_bit - 1))) != 0 {
55 ix = ix.wrapping_add(half_bit);
58 }
59 ix &= !(int_bit - 1);
60 } else if exponent == BIAS - 1 && ux > 0x3f000000 {
61 ix = (ix & 0x80000000) | 0x3f800000;
63 } else {
64 ix &= 0x80000000;
66 }
67 f32::from_bits(ix)
68}
69
70pub const fn round_ties_even(x: f64) -> f64 {
71 let mut ix: u64 = x.to_bits();
72 let ux = ix & 0x7fffffffffffffffu64;
73 const BIAS: i32 = 0x3ff;
74 const MANT_DIG: i32 = 53;
75 const MAX_EXP: i32 = 2 * BIAS + 1;
76 let exponent: i32 = (ux >> (MANT_DIG - 1)) as i32;
77 if exponent >= BIAS + MANT_DIG - 1 {
78 return if exponent == MAX_EXP {
80 x + x
82 } else {
83 x
84 };
85 } else if exponent >= BIAS {
86 let int_pos: i32 = (BIAS + MANT_DIG - 1) - exponent;
91 let half_pos: i32 = int_pos - 1;
92 let half_bit: u64 = 1u64 << half_pos;
93 let int_bit: u64 = 1u64 << int_pos;
94 if (ix & (int_bit | (half_bit - 1))) != 0 {
95 ix = ix.wrapping_add(half_bit);
98 }
99 ix &= !(int_bit - 1);
100 } else if exponent == BIAS - 1 && ux > 0x3fe0000000000000u64 {
101 ix = (ix & 0x8000000000000000u64) | 0x3ff0000000000000u64;
103 } else {
104 ix &= 0x8000000000000000u64;
106 }
107 f64::from_bits(ix)
108}
109
110pub(crate) trait RoundTiesEven {
111 fn round_ties_even_finite(self) -> Self;
112}
113
114impl RoundTiesEven for f32 {
115 #[inline]
116 fn round_ties_even_finite(self) -> Self {
117 #[cfg(any(
118 all(
119 any(target_arch = "x86", target_arch = "x86_64"),
120 target_feature = "sse4.1"
121 ),
122 target_arch = "aarch64"
123 ))]
124 {
125 self.round_ties_even()
126 }
127 #[cfg(not(any(
128 all(
129 any(target_arch = "x86", target_arch = "x86_64"),
130 target_feature = "sse4.1"
131 ),
132 target_arch = "aarch64"
133 )))]
134 {
135 roundf_ties_even(self)
136 }
137 }
138}
139
140impl RoundTiesEven for f64 {
141 #[inline]
142 fn round_ties_even_finite(self) -> Self {
143 #[cfg(any(
144 all(
145 any(target_arch = "x86", target_arch = "x86_64"),
146 target_feature = "sse4.1"
147 ),
148 target_arch = "aarch64"
149 ))]
150 {
151 self.round_ties_even()
152 }
153 #[cfg(not(any(
154 all(
155 any(target_arch = "x86", target_arch = "x86_64"),
156 target_feature = "sse4.1"
157 ),
158 target_arch = "aarch64"
159 )))]
160 {
161 round_ties_even(self)
162 }
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn test_roundf_ties_even() {
172 assert_eq!(roundf_ties_even(0f32), 0.0f32.round_ties_even());
173 assert_eq!(roundf_ties_even(0.5f32), 0.5f32.round_ties_even());
174 assert_eq!(roundf_ties_even(-0.5), (-0.5f32).round_ties_even());
175 assert_eq!(roundf_ties_even(1f32), 1.0f32.round_ties_even());
176 assert_eq!(roundf_ties_even(1.2f32), 1.2f32.round_ties_even());
177 assert_eq!(roundf_ties_even(-1.2f32), (-1.2f32).round_ties_even());
178 assert_eq!(roundf_ties_even(-1.6f32), (-1.6f32).round_ties_even());
179 assert_eq!(roundf_ties_even(-1.5f32), (-1.5f32).round_ties_even());
180 assert_eq!(roundf_ties_even(1.6f32), 1.6f32.round_ties_even());
181 assert_eq!(roundf_ties_even(1.5f32), 1.5f32.round_ties_even());
182 assert_eq!(roundf_ties_even(2.5f32), 2.5f32.round_ties_even());
183 assert_eq!(
184 roundf_ties_even(f32::INFINITY),
185 f32::INFINITY.round_ties_even()
186 );
187 assert_eq!(
188 roundf_ties_even(f32::NEG_INFINITY),
189 f32::NEG_INFINITY.round_ties_even()
190 );
191 assert!(roundf_ties_even(f32::NAN).is_nan());
192 }
193
194 #[test]
195 fn test_round_ties_even() {
196 assert_eq!(
197 round_ties_even(5.6916e-320),
198 (5.6916e-320f64).round_ties_even()
199 );
200 assert_eq!(round_ties_even(3f64), 3f64.round_ties_even());
201 assert_eq!(round_ties_even(2f64), 2f64.round_ties_even());
202 assert_eq!(round_ties_even(0.), 0.0f64.round_ties_even());
203 assert_eq!(round_ties_even(0.5), 0.5f64.round_ties_even());
204 assert_eq!(round_ties_even(-0.5), (-0.5f64).round_ties_even());
205 assert_eq!(round_ties_even(1.), 1.0f64.round_ties_even());
206 assert_eq!(round_ties_even(1.2), 1.2f64.round_ties_even());
207 assert_eq!(round_ties_even(-1.2), (-1.2f64).round_ties_even());
208 assert_eq!(round_ties_even(-1.6), (-1.6f64).round_ties_even());
209 assert_eq!(round_ties_even(-1.5), (-1.5f64).round_ties_even());
210 assert_eq!(round_ties_even(1.6), 1.6f64.round_ties_even());
211 assert_eq!(round_ties_even(1.5), 1.5f64.round_ties_even());
212 assert_eq!(round_ties_even(2.5), 2.5f64.round_ties_even());
213 assert_eq!(round_ties_even(-2.5), (-2.5f64).round_ties_even());
214 assert_eq!(
215 round_ties_even(f64::INFINITY),
216 f64::INFINITY.round_ties_even()
217 );
218 assert_eq!(
219 round_ties_even(f64::NEG_INFINITY),
220 f64::NEG_INFINITY.round_ties_even()
221 );
222 assert!(round_ties_even(f64::NAN).is_nan());
223 }
224}