zenith_float_num/common/
util.rs1use crate::{
4 defs::{Error, Word, WORD_BIT_SIZE, WORD_MAX, WORD_SIGNIFICANT_BIT},
5 RoundingMode,
6};
7
8#[cfg(test)]
9use crate::{num::ExactNumNumber, Sign, EXPONENT_MIN};
10
11#[cfg(test)]
12#[cfg(not(feature = "std"))]
13use alloc::vec::Vec;
14
15pub fn log2_ceil(mut n: usize) -> usize {
17 let mut ret = 0;
18 let mut sticky = 0;
19 while n > 1 {
20 if n & 1 != 0 {
21 sticky = 1;
22 }
23 ret += 1;
24 n >>= 1;
25 }
26 ret + sticky
27}
28
29pub fn log2_floor(mut n: usize) -> usize {
31 let mut ret = 0;
32 while n > 1 {
33 ret += 1;
34 n >>= 1;
35 }
36 ret
37}
38
39pub fn sqrt_int(a: u32) -> u32 {
41 let a = a as u64;
42 let mut x = a;
43 for _ in 0..20 {
44 if x == 0 {
45 break;
46 }
47 x = (a / x + x) >> 1;
48 }
49 x as u32
50}
51
52pub fn calc_mul_cost(p: usize) -> usize {
54 if p < 70 {
55 p * p
56 } else {
57 if p < 1625 {
59 sqrt_int((p * p * p) as u32) as usize
60 } else {
61 let q = sqrt_int(p as u32) as usize;
62 q * q * q
63 }
64 }
65}
66
67#[inline]
69pub fn calc_add_cost(p: usize) -> usize {
70 p
71}
72
73pub const MAX_PREC_RETRY: usize = 256;
75
76#[cfg(test)]
77pub const MAX_DEC_SCALE: usize = 1_000_000;
78
79#[inline]
81pub fn prec_retry_exhausted(p_wrk: usize, p: usize) -> bool {
82 p_wrk > p.saturating_add(WORD_BIT_SIZE.saturating_mul(MAX_PREC_RETRY))
83}
84
85#[inline]
87pub fn bump_prec_retry(p_wrk: &mut usize, p_inc: &mut usize, p: usize) -> Result<(), Error> {
88 if prec_retry_exhausted(*p_wrk, p) {
89 return Err(Error::PrecisionRetryExhausted);
90 }
91 *p_wrk += *p_inc;
92 *p_inc = round_p(*p_wrk / 5);
93 Ok(())
94}
95
96#[cfg(test)]
97pub const TEST_EXP_BOUND: crate::Exponent = 1024;
98
99#[cfg(test)]
100pub fn test_loop_count(full: usize) -> usize {
101 full.min(200)
102}
103
104#[inline]
106pub fn calc_sqrt_cost(p: usize, cost_mul: usize, cost_add: usize) -> usize {
107 let log3_estimate = (log2_floor(p) * 41349) >> 16;
108 log3_estimate * (5 * cost_mul + 2 * cost_add) / 2
109}
110
111#[inline(always)]
112pub fn add_carry(a: Word, b: Word, c: Word, r: &mut Word) -> Word {
113 #[cfg(target_arch = "x86_64")]
114 {
115 core::arch::x86_64::_addcarry_u64(c as u8, a, b, r) as Word
117 }
118
119 #[cfg(target_arch = "x86")]
120 {
121 core::arch::x86::_addcarry_u32(c as u8, a, b, r) as Word
123 }
124
125 #[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
126 {
127 use crate::defs::DoubleWord;
128 use crate::defs::WORD_BASE;
129
130 let mut s = c as DoubleWord + a as DoubleWord + b as DoubleWord;
131 if s >= WORD_BASE {
132 s -= WORD_BASE;
133 *r = s as Word;
134 1
135 } else {
136 *r = s as Word;
137 0
138 }
139 }
140}
141
142#[inline(always)]
143pub fn sub_borrow(a: Word, b: Word, c: Word, r: &mut Word) -> Word {
144 #[cfg(target_arch = "x86_64")]
145 {
146 core::arch::x86_64::_subborrow_u64(c as u8, a, b, r) as Word
148 }
149
150 #[cfg(target_arch = "x86")]
151 {
152 core::arch::x86::_subborrow_u32(c as u8, a, b, r) as Word
154 }
155
156 #[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
157 {
158 use crate::defs::DoubleWord;
159 use crate::defs::WORD_BASE;
160
161 let v1 = a as DoubleWord;
162 let v2 = b as DoubleWord + c as DoubleWord;
163
164 if v1 < v2 {
165 *r = (v1 + WORD_BASE - v2) as Word;
166 1
167 } else {
168 *r = (v1 - v2) as Word;
169 0
170 }
171 }
172}
173
174pub fn shift_slice_left(m: &mut [Word], n: usize) {
176 let idx = n / WORD_BIT_SIZE;
177 let shift = n % WORD_BIT_SIZE;
178 if idx >= m.len() {
179 m.fill(0);
180 } else if shift > 0 {
181 let l = m.len() - 1;
182 let end = m.as_mut_ptr();
183 unsafe {
184 let mut dst = end.add(l);
185 let mut src = end.add(l - idx);
186 loop {
187 if src > end {
188 let mut d = *src << shift;
189 src = src.sub(1);
190 d |= *src >> (WORD_BIT_SIZE - shift);
191 *dst = d;
192 dst = dst.sub(1);
193 } else {
194 break;
195 }
196 }
197 *dst = *src << shift;
198 }
199 m[0..idx].fill(0);
200 } else if idx > 0 {
201 let r = m.len() - idx;
202 m.copy_within(0..r, idx);
203 m[..idx].fill(0);
204 }
205}
206
207pub fn shift_slice_left_copy(m: &[Word], m2: &mut [Word], n: usize) {
209 let idx = n / WORD_BIT_SIZE;
210 let shift = n % WORD_BIT_SIZE;
211 if idx >= m2.len() {
212 m2.fill(0);
213 } else if shift > 0 {
214 m2[..idx].fill(0);
215 let mut dst = m2[idx..].iter_mut();
216 let src = m.iter();
217 let mut prev = 0;
218 for (a, b) in src.zip(dst.by_ref()) {
219 *b = (prev >> (WORD_BIT_SIZE - shift)) | (*a << shift);
220 prev = *a;
221 }
222 if let Some(b) = dst.next() {
223 *b = prev >> (WORD_BIT_SIZE - shift);
224 }
225 for b in dst {
226 *b = 0;
227 }
228 } else {
229 m2[..idx].fill(0);
230 let mut dst = m2[idx..].iter_mut();
231 for (a, b) in m.iter().zip(dst.by_ref()) {
232 *b = *a;
233 }
234 for b in dst {
235 *b = 0;
236 }
237 }
238}
239
240pub fn shift_slice_right(m: &mut [Word], n: usize) {
242 let idx = n / WORD_BIT_SIZE;
243 let shift = n % WORD_BIT_SIZE;
244 if idx >= m.len() {
245 m.fill(0);
246 } else if shift > 0 {
247 let l = m.len();
248 let mut dst = m.as_mut_ptr();
249 unsafe {
250 let end = dst.add(l - 1);
251 let mut src = dst.add(idx);
252 loop {
253 if src < end {
254 let mut d = *src >> shift;
255 src = src.add(1);
256 d |= *src << (WORD_BIT_SIZE - shift);
257 *dst = d;
258 dst = dst.add(1);
259 } else {
260 break;
261 }
262 }
263 *dst = *src >> shift;
264 }
265 m[l - idx..].fill(0);
266 } else if idx > 0 {
267 let r = m.len() - idx;
268 m.copy_within(idx.., 0);
269 m[r..].fill(0);
270 }
271}
272
273pub fn count_leading_zeroes_skip_first(m: &[Word]) -> usize {
274 let mut iter = m.iter().rev();
275 let mut w;
276 let mut ret = 0;
277
278 if let Some(v) = iter.next() {
279 w = *v & (WORD_MAX >> 1);
280
281 while w == 0 {
282 ret += WORD_BIT_SIZE;
283
284 w = match iter.next() {
285 Some(v) => *v,
286 None => break,
287 }
288 }
289
290 if w != 0 {
291 while w & WORD_SIGNIFICANT_BIT == 0 {
292 w <<= 1;
293 ret += 1;
294 }
295 }
296 }
297
298 ret
299}
300
301pub fn count_leading_ones(m: &[Word]) -> usize {
302 let mut ret = 0;
303
304 for &v in m.iter().rev() {
305 if v == WORD_MAX {
306 ret += WORD_BIT_SIZE;
307 } else {
308 let mut v = v;
309
310 while v & WORD_SIGNIFICANT_BIT != 0 {
311 v <<= 1;
312 ret += 1;
313 }
314
315 break;
316 }
317 }
318
319 ret
320}
321
322pub fn round_p(p: usize) -> usize {
324 ((p.saturating_add(WORD_BIT_SIZE - 1)) / WORD_BIT_SIZE) * WORD_BIT_SIZE
325}
326
327pub fn invert_rm_for_sign(rm: RoundingMode) -> RoundingMode {
329 if rm == RoundingMode::Up {
330 RoundingMode::Down
331 } else if rm == RoundingMode::Down {
332 RoundingMode::Up
333 } else {
334 rm
335 }
336}
337
338pub fn find_one_from(slice: &[Word], start_pos: usize) -> Option<usize> {
339 let start_idx = start_pos / WORD_BIT_SIZE;
340 if start_idx >= slice.len() {
341 None
342 } else {
343 let mut iter = slice.iter().rev().skip(start_idx);
344 if let Some(v) = iter.next() {
345 let mut d = *v;
346
347 let start_bit = start_pos % WORD_BIT_SIZE;
348 let mut shift = start_pos;
349
350 d <<= start_bit;
351
352 if d != 0 {
353 while d & WORD_SIGNIFICANT_BIT == 0 {
354 d <<= 1;
355 shift += 1;
356 }
357
358 return Some(shift);
359 }
360
361 shift += WORD_BIT_SIZE - start_bit;
362
363 for v in iter {
364 d = *v;
365
366 if d != 0 {
367 while d & WORD_SIGNIFICANT_BIT == 0 {
368 d <<= 1;
369 shift += 1;
370 }
371
372 return Some(shift);
373 }
374
375 shift += WORD_BIT_SIZE;
376 }
377 }
378
379 None
380 }
381}
382
383#[cfg(test)]
385pub(crate) fn random_subnormal(p: usize) -> ExactNumNumber {
386 let p = round_p(if p < 3 * WORD_BIT_SIZE { 3 * WORD_BIT_SIZE } else { p });
387 let n = p - crate::common::test_rng::random::<usize>() % (2 * WORD_BIT_SIZE) - 1;
388 let mut m = Vec::with_capacity(p / WORD_BIT_SIZE);
389
390 for _ in 0..n / WORD_BIT_SIZE {
391 m.push(crate::common::test_rng::random::<Word>());
392 }
393
394 if n % WORD_BIT_SIZE > 0 {
395 let w = (crate::common::test_rng::random::<Word>() | WORD_SIGNIFICANT_BIT)
396 >> (WORD_BIT_SIZE - n % WORD_BIT_SIZE);
397 m.push(w);
398 } else {
399 *m.last_mut().unwrap() |= WORD_SIGNIFICANT_BIT;
400 }
401
402 m.resize(p / WORD_BIT_SIZE, 0);
403
404 let s = if crate::common::test_rng::random::<u8>() & 1 == 0 {
405 Sign::Pos
406 } else {
407 Sign::Neg
408 };
409
410 ExactNumNumber::from_raw_parts(&m, n, s, EXPONENT_MIN, false).unwrap()
411}
412
413#[cfg(test)]
414#[inline]
415pub fn rand_p() -> usize {
416 crate::common::test_rng::random::<usize>() % 1000 + crate::defs::DEFAULT_P
417}