/rust/registry/src/index.crates.io-1949cf8c6b5b557f/lexical-parse-float-1.0.6/src/shared.rs
Line | Count | Source |
1 | | //! Shared utilities and algorithms. |
2 | | |
3 | | #![doc(hidden)] |
4 | | |
5 | | #[cfg(feature = "power-of-two")] |
6 | | use lexical_util::format::NumberFormat; |
7 | | use lexical_util::num::AsPrimitive; |
8 | | |
9 | | use crate::float::{ExtendedFloat80, RawFloat}; |
10 | | use crate::mask::{lower_n_halfway, lower_n_mask}; |
11 | | |
12 | | // 8 DIGIT |
13 | | // ------- |
14 | | |
15 | | /// Check if we can try to parse 8 digits at one. |
16 | | #[cfg(not(feature = "compact"))] |
17 | | macro_rules! can_try_parse_multidigit { |
18 | | ($iter:expr, $radix:expr) => { |
19 | | $iter.is_contiguous() && (cfg!(not(feature = "power-of-two")) || $radix <= 10) |
20 | | }; |
21 | | } |
22 | | |
23 | | // POWER2 |
24 | | // ------ |
25 | | |
26 | | /// Calculate the shift to move the significant digits into place. |
27 | | #[inline(always)] |
28 | 0 | pub fn calculate_shift<F: RawFloat>(power2: i32) -> i32 { |
29 | 0 | let mantissa_shift = 64 - F::MANTISSA_SIZE - 1; |
30 | 0 | if -power2 >= mantissa_shift { |
31 | 0 | -power2 + 1 |
32 | | } else { |
33 | 0 | mantissa_shift |
34 | | } |
35 | 0 | } |
36 | | |
37 | | /// Calculate the biased, binary exponent from the mantissa shift and exponent. |
38 | | #[inline(always)] |
39 | | #[cfg(feature = "power-of-two")] |
40 | | pub fn calculate_power2<F: RawFloat, const FORMAT: u128>(exponent: i64, ctlz: u32) -> i32 { |
41 | | let format = NumberFormat::<{ FORMAT }> {}; |
42 | | exponent as i32 * log2(format.exponent_base()) + F::EXPONENT_BIAS - ctlz as i32 |
43 | | } |
44 | | |
45 | | /// Bias for marking an invalid extended float. |
46 | | pub const INVALID_FP: i32 = i16::MIN as i32; |
47 | | |
48 | | // LOG2 |
49 | | // ---- |
50 | | |
51 | | /// Quick log2 that evaluates at compile time for the radix. |
52 | | /// Note that this may produce inaccurate results for other radixes: |
53 | | /// we don't care since it's only called for powers-of-two. |
54 | | #[inline(always)] |
55 | 11.3k | pub const fn log2(radix: u32) -> i32 { |
56 | 11.3k | match radix { |
57 | 0 | 2 => 1, |
58 | 0 | 4 => 2, |
59 | 0 | 8 => 3, |
60 | 0 | 16 => 4, |
61 | 0 | 32 => 5, |
62 | | // Fallthrough to 1 for non-power-of-two radixes. |
63 | 11.3k | _ => 1, |
64 | | } |
65 | 11.3k | } |
66 | | |
67 | | // STARTS WITH |
68 | | // ----------- |
69 | | |
70 | | /// Check if left iter starts with right iter. |
71 | | /// |
72 | | /// This optimizes decently well, to the following ASM for pure slices: |
73 | | /// |
74 | | /// ```text |
75 | | /// starts_with_slc: |
76 | | /// xor eax, eax |
77 | | /// .LBB0_1: |
78 | | /// cmp rcx, rax |
79 | | /// je .LBB0_2 |
80 | | /// cmp rsi, rax |
81 | | /// je .LBB0_5 |
82 | | /// movzx r8d, byte ptr [rdi + rax] |
83 | | /// lea r9, [rax + 1] |
84 | | /// cmp r8b, byte ptr [rdx + rax] |
85 | | /// mov rax, r9 |
86 | | /// je .LBB0_1 |
87 | | /// .LBB0_5: |
88 | | /// xor eax, eax |
89 | | /// ret |
90 | | /// .LBB0_2: |
91 | | /// mov al, 1 |
92 | | /// ret |
93 | | /// ``` |
94 | | #[cfg_attr(not(feature = "compact"), inline(always))] |
95 | 0 | pub fn starts_with<'a, 'b, Iter1, Iter2>(mut x: Iter1, mut y: Iter2) -> bool |
96 | 0 | where |
97 | 0 | Iter1: Iterator<Item = &'a u8>, |
98 | 0 | Iter2: Iterator<Item = &'b u8>, |
99 | | { |
100 | | loop { |
101 | | // Only call `next()` on x if y is not None, otherwise, |
102 | | // we may incorrectly consume an x character. |
103 | 0 | let yi = y.next(); |
104 | 0 | if yi.is_none() { |
105 | 0 | return true; |
106 | 0 | } else if x.next() != yi { |
107 | 0 | return false; |
108 | 0 | } |
109 | | } |
110 | 0 | } |
111 | | |
112 | | /// Check if left iter starts with right iter without case-sensitivity. |
113 | | /// |
114 | | /// This optimizes decently well, to the following ASM for pure slices: |
115 | | /// |
116 | | /// ```text |
117 | | /// starts_with_uncased: |
118 | | /// xor eax, eax |
119 | | /// .LBB1_1: |
120 | | /// cmp rcx, rax |
121 | | /// je .LBB1_2 |
122 | | /// cmp rsi, rax |
123 | | /// je .LBB1_5 |
124 | | /// movzx r8d, byte ptr [rdi + rax] |
125 | | /// xor r8b, byte ptr [rdx + rax] |
126 | | /// add rax, 1 |
127 | | /// test r8b, -33 |
128 | | /// je .LBB1_1 |
129 | | /// .LBB1_5: |
130 | | /// xor eax, eax |
131 | | /// ret |
132 | | /// .LBB1_2: |
133 | | /// mov al, 1 |
134 | | /// ret |
135 | | /// ``` |
136 | | #[cfg_attr(not(feature = "compact"), inline(always))] |
137 | | #[allow(clippy::unwrap_used)] // reason="yi cannot be none due to previous check" |
138 | 2.39k | pub fn starts_with_uncased<'a, 'b, Iter1, Iter2>(mut x: Iter1, mut y: Iter2) -> bool |
139 | 2.39k | where |
140 | 2.39k | Iter1: Iterator<Item = &'a u8>, |
141 | 2.39k | Iter2: Iterator<Item = &'b u8>, |
142 | | { |
143 | | // We use a faster optimization here for ASCII letters, which NaN |
144 | | // and infinite strings **must** be. [A-Z] is 0x41-0x5A, while |
145 | | // [a-z] is 0x61-0x7A. Therefore, the xor must be 0 or 32 if they |
146 | | // are case-insensitive equal, but only if at least 1 of the inputs |
147 | | // is an ASCII letter. |
148 | | loop { |
149 | 2.57k | let yi = y.next(); |
150 | 2.57k | if yi.is_none() { |
151 | 0 | return true; |
152 | 2.57k | } |
153 | 2.57k | let yi = *yi.unwrap(); |
154 | 2.57k | let is_not_equal = x.next().map_or(true, |&xi| { |
155 | 2.57k | let xor = xi ^ yi; |
156 | 2.57k | xor != 0 && xor != 0x20 |
157 | 2.57k | }); lexical_parse_float::shared::starts_with_uncased::<lexical_util::noskip::DigitsIterator<0xa0000000000000000000000000c>, core::slice::iter::Iter<u8>>::{closure#0}Line | Count | Source | 154 | 2.57k | let is_not_equal = x.next().map_or(true, |&xi| { | 155 | 2.57k | let xor = xi ^ yi; | 156 | 2.57k | xor != 0 && xor != 0x20 | 157 | 2.57k | }); |
Unexecuted instantiation: lexical_parse_float::shared::starts_with_uncased::<_, _>::{closure#0} |
158 | 2.57k | if is_not_equal { |
159 | 2.39k | return false; |
160 | 177 | } |
161 | | } |
162 | 2.39k | } lexical_parse_float::shared::starts_with_uncased::<lexical_util::noskip::DigitsIterator<0xa0000000000000000000000000c>, core::slice::iter::Iter<u8>> Line | Count | Source | 138 | 2.39k | pub fn starts_with_uncased<'a, 'b, Iter1, Iter2>(mut x: Iter1, mut y: Iter2) -> bool | 139 | 2.39k | where | 140 | 2.39k | Iter1: Iterator<Item = &'a u8>, | 141 | 2.39k | Iter2: Iterator<Item = &'b u8>, | 142 | | { | 143 | | // We use a faster optimization here for ASCII letters, which NaN | 144 | | // and infinite strings **must** be. [A-Z] is 0x41-0x5A, while | 145 | | // [a-z] is 0x61-0x7A. Therefore, the xor must be 0 or 32 if they | 146 | | // are case-insensitive equal, but only if at least 1 of the inputs | 147 | | // is an ASCII letter. | 148 | | loop { | 149 | 2.57k | let yi = y.next(); | 150 | 2.57k | if yi.is_none() { | 151 | 0 | return true; | 152 | 2.57k | } | 153 | 2.57k | let yi = *yi.unwrap(); | 154 | 2.57k | let is_not_equal = x.next().map_or(true, |&xi| { | 155 | | let xor = xi ^ yi; | 156 | | xor != 0 && xor != 0x20 | 157 | | }); | 158 | 2.57k | if is_not_equal { | 159 | 2.39k | return false; | 160 | 177 | } | 161 | | } | 162 | 2.39k | } |
Unexecuted instantiation: lexical_parse_float::shared::starts_with_uncased::<_, _> |
163 | | |
164 | | // ROUNDING |
165 | | // -------- |
166 | | |
167 | | /// Round an extended-precision float to the nearest machine float. |
168 | | /// |
169 | | /// Shifts the significant digits into place, adjusts the exponent, |
170 | | /// so it can be easily converted to a native float. |
171 | | #[cfg_attr(not(feature = "compact"), inline(always))] |
172 | 851 | pub fn round<F, Cb>(fp: &mut ExtendedFloat80, cb: Cb) |
173 | 851 | where |
174 | 851 | F: RawFloat, |
175 | 851 | Cb: Fn(&mut ExtendedFloat80, i32), |
176 | | { |
177 | 851 | let fp_inf = ExtendedFloat80 { |
178 | 851 | mant: 0, |
179 | 851 | exp: F::INFINITE_POWER, |
180 | 851 | }; |
181 | | |
182 | | // Calculate our shift in significant digits. |
183 | 851 | let mantissa_shift = 64 - F::MANTISSA_SIZE - 1; |
184 | | |
185 | | // Check for a denormal float, if after the shift the exponent is negative. |
186 | 851 | if -fp.exp >= mantissa_shift { |
187 | | // Have a denormal float that isn't a literal 0. |
188 | | // The extra 1 is to adjust for the denormal float, which is |
189 | | // `1 - F::EXPONENT_BIAS`. This works as before, because our |
190 | | // old logic rounded to `F::DENORMAL_EXPONENT` (now 1), and then |
191 | | // checked if `exp == F::DENORMAL_EXPONENT` and no hidden mask |
192 | | // bit was set. Here, we handle that here, rather than later. |
193 | | // |
194 | | // This might round-down to 0, but shift will be at **max** 65, |
195 | | // for halfway cases rounding towards 0. |
196 | 0 | let shift = -fp.exp + 1; |
197 | 0 | debug_assert!(shift <= 65); |
198 | 0 | cb(fp, shift.min(64)); |
199 | | // Check for round-up: if rounding-nearest carried us to the hidden bit. |
200 | 0 | fp.exp = (fp.mant >= F::HIDDEN_BIT_MASK.as_u64()) as i32; |
201 | 0 | return; |
202 | 851 | } |
203 | | |
204 | | // The float is normal, round to the hidden bit. |
205 | 851 | cb(fp, mantissa_shift); |
206 | | |
207 | | // Check if we carried, and if so, shift the bit to the hidden bit. |
208 | 851 | let carry_mask = F::CARRY_MASK.as_u64(); |
209 | 851 | if fp.mant & carry_mask == carry_mask { |
210 | 0 | fp.mant >>= 1; |
211 | 0 | fp.exp += 1; |
212 | 851 | } |
213 | | |
214 | | // Handle if we carried and check for overflow again. |
215 | 851 | if fp.exp >= F::INFINITE_POWER { |
216 | | // Exponent is above largest normal value, must be infinite. |
217 | 0 | *fp = fp_inf; |
218 | 0 | return; |
219 | 851 | } |
220 | | |
221 | | // Remove the hidden bit. |
222 | 851 | fp.mant &= F::MANTISSA_MASK.as_u64(); |
223 | 851 | } lexical_parse_float::shared::round::<f64, lexical_parse_float::slow::negative_digit_comp<f64, 0xa0000000000000000000000000c>::{closure#0}>Line | Count | Source | 172 | 338 | pub fn round<F, Cb>(fp: &mut ExtendedFloat80, cb: Cb) | 173 | 338 | where | 174 | 338 | F: RawFloat, | 175 | 338 | Cb: Fn(&mut ExtendedFloat80, i32), | 176 | | { | 177 | 338 | let fp_inf = ExtendedFloat80 { | 178 | 338 | mant: 0, | 179 | 338 | exp: F::INFINITE_POWER, | 180 | 338 | }; | 181 | | | 182 | | // Calculate our shift in significant digits. | 183 | 338 | let mantissa_shift = 64 - F::MANTISSA_SIZE - 1; | 184 | | | 185 | | // Check for a denormal float, if after the shift the exponent is negative. | 186 | 338 | if -fp.exp >= mantissa_shift { | 187 | | // Have a denormal float that isn't a literal 0. | 188 | | // The extra 1 is to adjust for the denormal float, which is | 189 | | // `1 - F::EXPONENT_BIAS`. This works as before, because our | 190 | | // old logic rounded to `F::DENORMAL_EXPONENT` (now 1), and then | 191 | | // checked if `exp == F::DENORMAL_EXPONENT` and no hidden mask | 192 | | // bit was set. Here, we handle that here, rather than later. | 193 | | // | 194 | | // This might round-down to 0, but shift will be at **max** 65, | 195 | | // for halfway cases rounding towards 0. | 196 | 0 | let shift = -fp.exp + 1; | 197 | 0 | debug_assert!(shift <= 65); | 198 | 0 | cb(fp, shift.min(64)); | 199 | | // Check for round-up: if rounding-nearest carried us to the hidden bit. | 200 | 0 | fp.exp = (fp.mant >= F::HIDDEN_BIT_MASK.as_u64()) as i32; | 201 | 0 | return; | 202 | 338 | } | 203 | | | 204 | | // The float is normal, round to the hidden bit. | 205 | 338 | cb(fp, mantissa_shift); | 206 | | | 207 | | // Check if we carried, and if so, shift the bit to the hidden bit. | 208 | 338 | let carry_mask = F::CARRY_MASK.as_u64(); | 209 | 338 | if fp.mant & carry_mask == carry_mask { | 210 | 0 | fp.mant >>= 1; | 211 | 0 | fp.exp += 1; | 212 | 338 | } | 213 | | | 214 | | // Handle if we carried and check for overflow again. | 215 | 338 | if fp.exp >= F::INFINITE_POWER { | 216 | | // Exponent is above largest normal value, must be infinite. | 217 | 0 | *fp = fp_inf; | 218 | 0 | return; | 219 | 338 | } | 220 | | | 221 | | // Remove the hidden bit. | 222 | 338 | fp.mant &= F::MANTISSA_MASK.as_u64(); | 223 | 338 | } |
lexical_parse_float::shared::round::<f64, lexical_parse_float::slow::positive_digit_comp<f64, 0xa0000000000000000000000000c>::{closure#0}>Line | Count | Source | 172 | 175 | pub fn round<F, Cb>(fp: &mut ExtendedFloat80, cb: Cb) | 173 | 175 | where | 174 | 175 | F: RawFloat, | 175 | 175 | Cb: Fn(&mut ExtendedFloat80, i32), | 176 | | { | 177 | 175 | let fp_inf = ExtendedFloat80 { | 178 | 175 | mant: 0, | 179 | 175 | exp: F::INFINITE_POWER, | 180 | 175 | }; | 181 | | | 182 | | // Calculate our shift in significant digits. | 183 | 175 | let mantissa_shift = 64 - F::MANTISSA_SIZE - 1; | 184 | | | 185 | | // Check for a denormal float, if after the shift the exponent is negative. | 186 | 175 | if -fp.exp >= mantissa_shift { | 187 | | // Have a denormal float that isn't a literal 0. | 188 | | // The extra 1 is to adjust for the denormal float, which is | 189 | | // `1 - F::EXPONENT_BIAS`. This works as before, because our | 190 | | // old logic rounded to `F::DENORMAL_EXPONENT` (now 1), and then | 191 | | // checked if `exp == F::DENORMAL_EXPONENT` and no hidden mask | 192 | | // bit was set. Here, we handle that here, rather than later. | 193 | | // | 194 | | // This might round-down to 0, but shift will be at **max** 65, | 195 | | // for halfway cases rounding towards 0. | 196 | 0 | let shift = -fp.exp + 1; | 197 | 0 | debug_assert!(shift <= 65); | 198 | 0 | cb(fp, shift.min(64)); | 199 | | // Check for round-up: if rounding-nearest carried us to the hidden bit. | 200 | 0 | fp.exp = (fp.mant >= F::HIDDEN_BIT_MASK.as_u64()) as i32; | 201 | 0 | return; | 202 | 175 | } | 203 | | | 204 | | // The float is normal, round to the hidden bit. | 205 | 175 | cb(fp, mantissa_shift); | 206 | | | 207 | | // Check if we carried, and if so, shift the bit to the hidden bit. | 208 | 175 | let carry_mask = F::CARRY_MASK.as_u64(); | 209 | 175 | if fp.mant & carry_mask == carry_mask { | 210 | 0 | fp.mant >>= 1; | 211 | 0 | fp.exp += 1; | 212 | 175 | } | 213 | | | 214 | | // Handle if we carried and check for overflow again. | 215 | 175 | if fp.exp >= F::INFINITE_POWER { | 216 | | // Exponent is above largest normal value, must be infinite. | 217 | 0 | *fp = fp_inf; | 218 | 0 | return; | 219 | 175 | } | 220 | | | 221 | | // Remove the hidden bit. | 222 | 175 | fp.mant &= F::MANTISSA_MASK.as_u64(); | 223 | 175 | } |
lexical_parse_float::shared::round::<f64, lexical_parse_float::shared::round_down> Line | Count | Source | 172 | 338 | pub fn round<F, Cb>(fp: &mut ExtendedFloat80, cb: Cb) | 173 | 338 | where | 174 | 338 | F: RawFloat, | 175 | 338 | Cb: Fn(&mut ExtendedFloat80, i32), | 176 | | { | 177 | 338 | let fp_inf = ExtendedFloat80 { | 178 | 338 | mant: 0, | 179 | 338 | exp: F::INFINITE_POWER, | 180 | 338 | }; | 181 | | | 182 | | // Calculate our shift in significant digits. | 183 | 338 | let mantissa_shift = 64 - F::MANTISSA_SIZE - 1; | 184 | | | 185 | | // Check for a denormal float, if after the shift the exponent is negative. | 186 | 338 | if -fp.exp >= mantissa_shift { | 187 | | // Have a denormal float that isn't a literal 0. | 188 | | // The extra 1 is to adjust for the denormal float, which is | 189 | | // `1 - F::EXPONENT_BIAS`. This works as before, because our | 190 | | // old logic rounded to `F::DENORMAL_EXPONENT` (now 1), and then | 191 | | // checked if `exp == F::DENORMAL_EXPONENT` and no hidden mask | 192 | | // bit was set. Here, we handle that here, rather than later. | 193 | | // | 194 | | // This might round-down to 0, but shift will be at **max** 65, | 195 | | // for halfway cases rounding towards 0. | 196 | 0 | let shift = -fp.exp + 1; | 197 | 0 | debug_assert!(shift <= 65); | 198 | 0 | cb(fp, shift.min(64)); | 199 | | // Check for round-up: if rounding-nearest carried us to the hidden bit. | 200 | 0 | fp.exp = (fp.mant >= F::HIDDEN_BIT_MASK.as_u64()) as i32; | 201 | 0 | return; | 202 | 338 | } | 203 | | | 204 | | // The float is normal, round to the hidden bit. | 205 | 338 | cb(fp, mantissa_shift); | 206 | | | 207 | | // Check if we carried, and if so, shift the bit to the hidden bit. | 208 | 338 | let carry_mask = F::CARRY_MASK.as_u64(); | 209 | 338 | if fp.mant & carry_mask == carry_mask { | 210 | 0 | fp.mant >>= 1; | 211 | 0 | fp.exp += 1; | 212 | 338 | } | 213 | | | 214 | | // Handle if we carried and check for overflow again. | 215 | 338 | if fp.exp >= F::INFINITE_POWER { | 216 | | // Exponent is above largest normal value, must be infinite. | 217 | 0 | *fp = fp_inf; | 218 | 0 | return; | 219 | 338 | } | 220 | | | 221 | | // Remove the hidden bit. | 222 | 338 | fp.mant &= F::MANTISSA_MASK.as_u64(); | 223 | 338 | } |
Unexecuted instantiation: lexical_parse_float::shared::round::<_, _> |
224 | | |
225 | | /// Shift right N-bytes and round towards a direction. |
226 | | /// |
227 | | /// Callback should take the following parameters: |
228 | | /// 1. `is_odd` |
229 | | /// 1. `is_halfway` |
230 | | /// 1. `is_above` |
231 | | #[cfg_attr(not(feature = "compact"), inline(always))] |
232 | 513 | pub fn round_nearest_tie_even<Cb>(fp: &mut ExtendedFloat80, shift: i32, cb: Cb) |
233 | 513 | where |
234 | 513 | // `is_odd`, `is_halfway`, `is_above` |
235 | 513 | Cb: Fn(bool, bool, bool) -> bool, |
236 | | { |
237 | | // Ensure we've already handled denormal values that underflow. |
238 | 513 | debug_assert!(shift <= 64); |
239 | | |
240 | | // Extract the truncated bits using mask. |
241 | | // Calculate if the value of the truncated bits are either above |
242 | | // the mid-way point, or equal to it. |
243 | | // |
244 | | // For example, for 4 truncated bytes, the mask would be 0b1111 |
245 | | // and the midway point would be 0b1000. |
246 | 513 | let mask = lower_n_mask(shift as u64); |
247 | 513 | let halfway = lower_n_halfway(shift as u64); |
248 | 513 | let truncated_bits = fp.mant & mask; |
249 | 513 | let is_above = truncated_bits > halfway; |
250 | 513 | let is_halfway = truncated_bits == halfway; |
251 | | |
252 | | // Bit shift so the leading bit is in the hidden bit. |
253 | | // This optimizes pretty well: |
254 | | // ```text |
255 | | // mov ecx, esi |
256 | | // shr rdi, cl |
257 | | // xor eax, eax |
258 | | // cmp esi, 64 |
259 | | // cmovne rax, rdi |
260 | | // ret |
261 | | // ``` |
262 | 513 | fp.mant = match shift == 64 { |
263 | 0 | true => 0, |
264 | 513 | false => fp.mant >> shift, |
265 | | }; |
266 | 513 | fp.exp += shift; |
267 | | |
268 | | // Extract the last bit after shifting (and determine if it is odd). |
269 | 513 | let is_odd = fp.mant & 1 == 1; |
270 | | |
271 | | // Calculate if we need to roundup. |
272 | | // We need to roundup if we are above halfway, or if we are odd |
273 | | // and at half-way (need to tie-to-even). Avoid the branch here. |
274 | 513 | fp.mant += cb(is_odd, is_halfway, is_above) as u64; |
275 | 513 | } lexical_parse_float::shared::round_nearest_tie_even::<lexical_parse_float::slow::negative_digit_comp<f64, 0xa0000000000000000000000000c>::{closure#0}::{closure#0}>Line | Count | Source | 232 | 338 | pub fn round_nearest_tie_even<Cb>(fp: &mut ExtendedFloat80, shift: i32, cb: Cb) | 233 | 338 | where | 234 | 338 | // `is_odd`, `is_halfway`, `is_above` | 235 | 338 | Cb: Fn(bool, bool, bool) -> bool, | 236 | | { | 237 | | // Ensure we've already handled denormal values that underflow. | 238 | 338 | debug_assert!(shift <= 64); | 239 | | | 240 | | // Extract the truncated bits using mask. | 241 | | // Calculate if the value of the truncated bits are either above | 242 | | // the mid-way point, or equal to it. | 243 | | // | 244 | | // For example, for 4 truncated bytes, the mask would be 0b1111 | 245 | | // and the midway point would be 0b1000. | 246 | 338 | let mask = lower_n_mask(shift as u64); | 247 | 338 | let halfway = lower_n_halfway(shift as u64); | 248 | 338 | let truncated_bits = fp.mant & mask; | 249 | 338 | let is_above = truncated_bits > halfway; | 250 | 338 | let is_halfway = truncated_bits == halfway; | 251 | | | 252 | | // Bit shift so the leading bit is in the hidden bit. | 253 | | // This optimizes pretty well: | 254 | | // ```text | 255 | | // mov ecx, esi | 256 | | // shr rdi, cl | 257 | | // xor eax, eax | 258 | | // cmp esi, 64 | 259 | | // cmovne rax, rdi | 260 | | // ret | 261 | | // ``` | 262 | 338 | fp.mant = match shift == 64 { | 263 | 0 | true => 0, | 264 | 338 | false => fp.mant >> shift, | 265 | | }; | 266 | 338 | fp.exp += shift; | 267 | | | 268 | | // Extract the last bit after shifting (and determine if it is odd). | 269 | 338 | let is_odd = fp.mant & 1 == 1; | 270 | | | 271 | | // Calculate if we need to roundup. | 272 | | // We need to roundup if we are above halfway, or if we are odd | 273 | | // and at half-way (need to tie-to-even). Avoid the branch here. | 274 | 338 | fp.mant += cb(is_odd, is_halfway, is_above) as u64; | 275 | 338 | } |
lexical_parse_float::shared::round_nearest_tie_even::<lexical_parse_float::slow::positive_digit_comp<f64, 0xa0000000000000000000000000c>::{closure#0}::{closure#0}>Line | Count | Source | 232 | 175 | pub fn round_nearest_tie_even<Cb>(fp: &mut ExtendedFloat80, shift: i32, cb: Cb) | 233 | 175 | where | 234 | 175 | // `is_odd`, `is_halfway`, `is_above` | 235 | 175 | Cb: Fn(bool, bool, bool) -> bool, | 236 | | { | 237 | | // Ensure we've already handled denormal values that underflow. | 238 | 175 | debug_assert!(shift <= 64); | 239 | | | 240 | | // Extract the truncated bits using mask. | 241 | | // Calculate if the value of the truncated bits are either above | 242 | | // the mid-way point, or equal to it. | 243 | | // | 244 | | // For example, for 4 truncated bytes, the mask would be 0b1111 | 245 | | // and the midway point would be 0b1000. | 246 | 175 | let mask = lower_n_mask(shift as u64); | 247 | 175 | let halfway = lower_n_halfway(shift as u64); | 248 | 175 | let truncated_bits = fp.mant & mask; | 249 | 175 | let is_above = truncated_bits > halfway; | 250 | 175 | let is_halfway = truncated_bits == halfway; | 251 | | | 252 | | // Bit shift so the leading bit is in the hidden bit. | 253 | | // This optimizes pretty well: | 254 | | // ```text | 255 | | // mov ecx, esi | 256 | | // shr rdi, cl | 257 | | // xor eax, eax | 258 | | // cmp esi, 64 | 259 | | // cmovne rax, rdi | 260 | | // ret | 261 | | // ``` | 262 | 175 | fp.mant = match shift == 64 { | 263 | 0 | true => 0, | 264 | 175 | false => fp.mant >> shift, | 265 | | }; | 266 | 175 | fp.exp += shift; | 267 | | | 268 | | // Extract the last bit after shifting (and determine if it is odd). | 269 | 175 | let is_odd = fp.mant & 1 == 1; | 270 | | | 271 | | // Calculate if we need to roundup. | 272 | | // We need to roundup if we are above halfway, or if we are odd | 273 | | // and at half-way (need to tie-to-even). Avoid the branch here. | 274 | 175 | fp.mant += cb(is_odd, is_halfway, is_above) as u64; | 275 | 175 | } |
Unexecuted instantiation: lexical_parse_float::shared::round_nearest_tie_even::<_> |
276 | | |
277 | | /// Round our significant digits into place, truncating them. |
278 | | #[cfg_attr(not(feature = "compact"), inline(always))] |
279 | 338 | pub fn round_down(fp: &mut ExtendedFloat80, shift: i32) { |
280 | | // Might have a shift greater than 64 if we have an error. |
281 | 338 | fp.mant = match shift == 64 { |
282 | 0 | true => 0, |
283 | 338 | false => fp.mant >> shift, |
284 | | }; |
285 | 338 | fp.exp += shift; |
286 | 338 | } |