ruint/algorithms/
mul_redc.rs1use super::addmul;
2use core::iter::zip;
3
4#[allow(clippy::cognitive_complexity)] #[inline]
7pub fn mul_redc(a: &[u64], b: &[u64], result: &mut [u64], m: &[u64], inv: u64) {
8 debug_assert!(!m.is_empty());
9 debug_assert_eq!(a.len(), m.len());
10 debug_assert_eq!(b.len(), m.len());
11 debug_assert_eq!(result.len(), m.len());
12 debug_assert_eq!(inv.wrapping_mul(m[0]), u64::MAX);
13
14 let mut temp = vec![0; 2 * m.len() + 1];
17 addmul(&mut temp, a, b);
18
19 for i in 0..m.len() {
21 let u = temp[i].wrapping_mul(inv);
22
23 let mut carry = 0;
25 #[allow(clippy::cast_possible_truncation)] for j in 0..m.len() {
27 carry += u128::from(temp[i + j]) + u128::from(m[j]) * u128::from(u);
28 temp[i + j] = carry as u64;
29 carry >>= 64;
30 }
31 #[allow(clippy::cast_possible_truncation)] for j in m.len()..(temp.len() - i) {
33 carry += u128::from(temp[i + j]);
34 temp[i + j] = carry as u64;
35 carry >>= 64;
36 }
37 debug_assert!(carry == 0);
38 }
39 debug_assert!(temp[temp.len() - 1] <= 1); result.copy_from_slice(&temp[m.len()..2 * m.len()]);
43
44 let mut reduce = true;
46 if temp[temp.len() - 1] == 0 {
48 for (r, m) in zip(result.iter().rev(), m.iter().rev()) {
49 if r < m {
50 reduce = false;
51 break;
52 }
53 if r > m {
54 break;
55 }
56 }
57 }
58 if reduce {
59 let mut carry = 0;
61 #[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_sign_loss)] for (r, m) in zip(result.iter_mut(), m.iter().copied()) {
64 carry += i128::from(*r) - i128::from(m);
65 *r = carry as u64;
66 carry >>= 64; }
68 debug_assert!(carry == 0 || temp[temp.len() - 1] == 1);
69 }
70}