1#![allow(dead_code)]
4#![allow(clippy::identity_op)]
5
6use stdlib::num::NonZeroU64;
7use num_traits::AsPrimitive;
8
9use crate::*;
10use crate::rounding::{NonDigitRoundingData, InsigData};
11
12use super::log10;
13
14use crate::bigdigit::{
15 radix::{RadixType, RadixPowerOfTen, RADIX_u64, RADIX_10_u8, RADIX_10p19_u64},
16 endian::{Endianness, LittleEndian, BigEndian},
17 digitvec::{DigitVec, DigitSlice},
18};
19
20type BigDigitVec = DigitVec<RADIX_u64, LittleEndian>;
21type BigDigitVecBe = DigitVec<RADIX_u64, BigEndian>;
22type BigDigitSliceU64<'a> = DigitSlice<'a, RADIX_u64, LittleEndian>;
23
24type BigDigitVecP19 = DigitVec<RADIX_10p19_u64, LittleEndian>;
25type BigDigitSliceP19<'a> = DigitSlice<'a, RADIX_10p19_u64, LittleEndian>;
26
27type SmallDigitVec = DigitVec<RADIX_10_u8, LittleEndian>;
28
29const BASE2_BIGINT_MUL_THRESHOLD: u64 = 128;
30
31
32pub(crate) fn multiply_decimals_with_context<'a, A, B>(
33 dest: &mut BigDecimal,
34 a: A,
35 b: B,
36 ctx: &Context,
37) where
38 A: Into<BigDecimalRef<'a>>,
39 B: Into<BigDecimalRef<'a>>,
40{
41 let a = a.into();
42 let b = b.into();
43
44 impl_multiply_decimals_with_context(dest, a, b, ctx);
45}
46
47pub fn impl_multiply_decimals_with_context(
48 dest: &mut BigDecimal,
49 a: BigDecimalRef,
50 b: BigDecimalRef,
51 ctx: &Context,
52) {
53 if a.is_zero() || b.is_zero() {
54 *dest = BigDecimal::zero();
55 return;
56 }
57
58 let sign = a.sign() * b.sign();
59 let rounding_data = NonDigitRoundingData {
60 sign: sign,
61 mode: ctx.rounding_mode(),
62 };
63
64 let a_uint = a.digits;
65 let b_uint = b.digits;
66
67 match (a, b.is_one_quickcheck(), b, a.is_one_quickcheck()) {
68 (x, Some(true), _, _) | (_, _, x, Some(true)) => {
69 let WithScale {
70 value: rounded_uint,
71 scale: rounded_scale,
72 } = rounding_data.round_biguint_to_prec(x.digits.clone(), ctx.precision());
73
74 dest.scale = x.scale + rounded_scale;
75 dest.int_val = BigInt::from_biguint(sign, rounded_uint);
76 return;
77 }
78 _ => {}
79 }
80
81 if let (Some(x), Some(y)) = (a_uint.to_u64(), b_uint.to_u64()) {
82 multiply_scaled_u64_into_decimal(
83 dest,
84 WithScale { value: x, scale: a.scale },
85 WithScale { value: y, scale: b.scale },
86 ctx.precision(),
87 rounding_data,
88 );
89 if true {
match (&dest.sign(), &sign) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_eq!(dest.sign(), sign);
90 return;
91 }
92
93 let a_vec = BigDigitVec::from(a_uint);
94 let b_vec = BigDigitVec::from(b_uint);
95
96 let digit_vec = BigDigitVec::new();
97 let mut digit_vec_scale = WithScale::from((digit_vec, 0));
98
99 multiply_scaled_u64_slices_with_prec_into(
100 &mut digit_vec_scale,
101 WithScale { value: a_vec.as_digit_slice(), scale: a.scale },
102 WithScale { value: b_vec.as_digit_slice(), scale: b.scale },
103 ctx.precision(),
104 rounding_data,
105 );
106
107 dest.int_val = BigInt::from_biguint(sign, digit_vec_scale.value.into());
108 dest.scale = digit_vec_scale.scale;
109}
110
111pub(crate) fn multiply_scaled_u64_into_decimal(
112 dest: &mut BigDecimal,
113 a: WithScale<u64>,
114 b: WithScale<u64>,
115 prec: NonZeroU64,
116 rounding_data: NonDigitRoundingData,
117) {
118 use crate::arithmetic::decimal::count_digits_u128;
119
120 let mut product = a.value as u128 * b.value as u128;
121 let digit_count = count_digits_u128(product) as u64;
122
123 let mut digits_to_remove = digit_count.saturating_sub(prec.get()) as u32;
124
125 if digits_to_remove == 0 {
126 dest.int_val = BigInt::from_biguint(rounding_data.sign, product.into());
127 dest.scale = a.scale + b.scale;
128 return;
129 }
130
131 let shifter = 10u128.pow(digits_to_remove - 1);
132 let (hi, trailing) = product.div_rem(&shifter);
133 let (shifted_product, insig_digit) = hi.div_rem(&10);
134 let sig_digit = (shifted_product % 10) as u8;
135
136 let rounded_digit = rounding_data.round_pair(
137 (sig_digit, insig_digit as u8),
138 trailing == 0,
139 );
140
141 product = shifted_product - sig_digit as u128 + rounded_digit as u128;
142
143 if rounded_digit >= 10 {
144 if true {
match (&rounded_digit, &10) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_eq!(rounded_digit, 10);
145
146 let old_digit_count = digit_count - digits_to_remove as u64;
147 if true {
match (&old_digit_count, &(count_digits_u128(shifted_product) as u64)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_eq!(old_digit_count, count_digits_u128(shifted_product) as u64);
148
149 let rounded_digit_count = count_digits_u128(product) as u64;
150 if old_digit_count != rounded_digit_count {
151 if true {
match (&rounded_digit_count, &(old_digit_count + 1)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_eq!(rounded_digit_count, old_digit_count + 1);
152 product /= 10;
153 digits_to_remove += 1;
154 }
155 }
156
157 let digit_array = mul_split_u128_to_u32x4(product);
158 dest.int_val.assign_from_slice(rounding_data.sign, &digit_array);
159
160 dest.scale = a.scale + b.scale - digits_to_remove as i64;
161}
162
163pub(crate) fn multiply_at_product_index<R, E, EA, EB>(
178 dest: &mut DigitVec<R, E>,
179 a: DigitSlice<R, EA>,
180 b: DigitSlice<R, EB>,
181 idx: usize,
182) where
183 R: RadixType,
184 E: Endianness,
185 EA: Endianness,
186 EB: Endianness,
187{
188 if true {
if !(b.len() <= a.len()) {
::core::panicking::panic("assertion failed: b.len() <= a.len()")
};
};debug_assert!(b.len() <= a.len());
189
190 dest.resize((a.len() + b.len()).saturating_sub(idx));
191
192 let b_idx_min = idx.saturating_sub(a.len() - 1);
193
194 for (b_idx, &x) in b.iter_le().enumerate().skip(b_idx_min).rev() {
195 let a_idx_min = idx.saturating_sub(b_idx);
196 if true {
if !(a_idx_min < a.len()) {
::core::panicking::panic("assertion failed: a_idx_min < a.len()")
};
};debug_assert!(a_idx_min < a.len());
197
198 let dest_idx = a_idx_min + b_idx - idx;
199
200 let mut dest_digits = dest.iter_le_mut().skip(dest_idx);
201 let mut carry = Zero::zero();
202 for &y in a.iter_le().skip(a_idx_min) {
203 R::carrying_mul_add_inplace(
204 x, y, dest_digits.next().unwrap(), &mut carry
205 );
206 }
207 R::add_carry_into(dest_digits, &mut carry);
208 if !carry.is_zero() {
209 dest.push_significant_digit(carry);
210 }
211 }
212}
213
214
215pub(crate) fn multiply_at_idx_into<R: RadixType>(
216 dest: &mut DigitVec<R, LittleEndian>,
217 a: DigitSlice<R, LittleEndian>,
218 b: DigitSlice<R, LittleEndian>,
219 idx: usize,
220) {
221 if true {
if !(a.len() + b.len() <= dest.len() + idx) {
::core::panicking::panic("assertion failed: a.len() + b.len() <= dest.len() + idx")
};
};debug_assert!(a.len() + b.len() <= dest.len() + idx);
222 for (ia, &da) in a.digits.iter().enumerate() {
223 if da.is_zero() {
224 continue;
225 }
226 let mut carry = Zero::zero();
227 for (&db, result) in b.digits.iter().zip(dest.digits.iter_mut().skip(idx + ia)) {
228 R::carrying_mul_add_inplace(da, db, result, &mut carry);
229 }
230 dest.add_value_at(idx + ia + b.len(), carry);
231 }
232}
233
234pub(crate) fn multiply_big_int_with_ctx(a: &BigInt, b: &BigInt, ctx: Context) -> WithScale<BigInt> {
235 let sign = a.sign() * b.sign();
236 let rounding_data = NonDigitRoundingData {
238 sign: sign,
239 mode: ctx.rounding_mode(),
240 };
241
242 if a.bits() + b.bits() < BASE2_BIGINT_MUL_THRESHOLD {
244 return ctx.round_bigint(a * b);
245 }
246
247 let mut tmp = Vec::new();
248 let a_p19_vec = BigDigitVecP19::from_biguint_using_tmp(a.magnitude(), &mut tmp);
249 let b_p19_vec = BigDigitVecP19::from_biguint_using_tmp(b.magnitude(), &mut tmp);
250
251 let mut result = WithScale::default();
252 multiply_slices_with_prec_into_p19(
253 &mut result,
254 a_p19_vec.as_digit_slice(),
255 b_p19_vec.as_digit_slice(),
256 ctx.precision(),
257 rounding_data
258 );
259
260 WithScale {
261 scale: result.scale,
262 value: result.value.into_bigint(sign),
263 }
264}
265
266pub(crate) fn multiply_slices_with_prec_into_p19(
274 dest: &mut WithScale<BigDigitVecP19>,
275 a: BigDigitSliceP19,
276 b: BigDigitSliceP19,
277 prec: NonZeroU64,
278 rounding: NonDigitRoundingData
279) {
280 multiply_slices_with_prec_into_p19_z(dest, a, b, prec, rounding, true)
281}
282
283
284pub(crate) fn multiply_slices_with_prec_into_p19_z(
292 dest: &mut WithScale<BigDigitVecP19>,
293 a: BigDigitSliceP19,
294 b: BigDigitSliceP19,
295 prec: NonZeroU64,
296 rounding: NonDigitRoundingData,
297 assume_trailing_zeros: bool,
298) {
299 use super::bigdigit::alignment::BigDigitSplitter;
300 use super::bigdigit::alignment::BigDigitSliceSplitterIter;
301 type R = RADIX_10p19_u64;
302
303 if a.len() < b.len() {
304 return multiply_slices_with_prec_into_p19_z(dest, b, a, prec, rounding, assume_trailing_zeros);
306 }
307
308 dest.value.clear();
309
310 if b.is_all_zeros() || a.is_all_zeros() {
311 return;
313 }
314
315 if true {
match (&a.len(), &0) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = ::core::panicking::AssertKind::Ne;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_ne!(a.len(), 0);
316 if true {
match (&b.len(), &0) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = ::core::panicking::AssertKind::Ne;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_ne!(b.len(), 0);
317
318 let WithScale { value: dest, scale: result_scale } = dest;
319
320 let pessimistic_product_digit_count = (a.len() + b.len() - 2) * R::DIGITS + 1;
322
323 let max_digit_sum_width = (2.0 * log10(R::max() as f64) + log10(b.len() as f64)).ceil() as usize;
328 let max_bigdigit_sum_width = R::divceil_digit_count(max_digit_sum_width);
329 let digits_to_skip = pessimistic_product_digit_count.saturating_sub(prec.get() as usize + 1);
331 let bigdigits_to_skip = R::divceil_digit_count(digits_to_skip)
332 .saturating_sub(max_bigdigit_sum_width);
333
334 let a_start;
335 let b_start;
336 if bigdigits_to_skip == 0 {
337 a_start = 0;
339 b_start = 0;
340 } else {
341 a_start = bigdigits_to_skip.saturating_sub(b.len());
344 b_start = bigdigits_to_skip.saturating_sub(a.len());
345 }
346
347 let a_sig = a.trim_insignificant(a_start);
348 let b_sig = b.trim_insignificant(b_start);
349
350 let a_sig_digit_count = a_sig.count_decimal_digits();
351 let b_sig_digit_count = b_sig.count_decimal_digits();
352
353 let max_sigproduct_bigdigit_count = R::divceil_digit_count(a_sig_digit_count + b_sig_digit_count + 1);
355 let mut product =
356 BigDigitVecP19::with_capacity(max_sigproduct_bigdigit_count + max_bigdigit_sum_width + 1);
357
358 *result_scale -= (R::DIGITS * bigdigits_to_skip) as i64;
359
360 multiply_at_product_index(&mut product, a, b, bigdigits_to_skip);
361 product.remove_leading_zeros();
362
363 let product_digit_count = product.count_decimal_digits();
364
365 let digits_to_remove = product_digit_count.saturating_sub(prec.get() as usize);
367 if digits_to_remove == 0 {
368 if true {
match (&a_start, &0) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_eq!(a_start, 0);
369 if true {
match (&b_start, &0) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_eq!(b_start, 0);
370 if true {
match (&bigdigits_to_skip, &0) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_eq!(bigdigits_to_skip, 0);
371
372 *dest = product;
374 return;
375 }
376
377 *result_scale -= digits_to_remove as i64;
379
380 let trailing_zeros = assume_trailing_zeros && calculate_partial_product_trailing_zeros(
384 &mut product, a, b, bigdigits_to_skip, digits_to_remove
385 );
386
387 let insig_digit = product.shift_n_digits_returning_high(digits_to_remove);
389 let sig_digit = (product.digits[0] % 10) as u8;
390
391 let insig_rounding_data = InsigData {
392 rounding_data: rounding,
393 digit: insig_digit,
394 trailing_zeros,
395 };
396
397 let rounded_digit = insig_rounding_data.round_digit(sig_digit);
398
399 let mut carry = rounded_digit as u64;
400
401 product.digits[0] -= sig_digit as u64;
402
403 R::add_carry_into_slice(
404 &mut product.digits, &mut carry
405 );
406
407 if carry != 0 {
408 if true {
if !product.digits.iter().all(|&d| d == 0) {
::core::panicking::panic("assertion failed: product.digits.iter().all(|&d| d == 0)")
};
};debug_assert!(product.digits.iter().all(|&d| d == 0));
409 *result_scale -= 1;
410 *product.digits.last_mut().unwrap() = (R::RADIX as u64) / 10;
411 }
412
413 if rounded_digit == 10 && product.count_decimal_digits() != prec.get() as usize {
414 *result_scale -= 1;
415
416 if let Some((hi, zeros)) = product.digits.split_last_mut() {
417 if true {
if !(*hi >= 10) {
::core::panicking::panic("assertion failed: *hi >= 10")
};
};debug_assert!(*hi >= 10);
418 if true {
if !zeros.iter().all(|&d| d == 0) {
::core::panicking::panic("assertion failed: zeros.iter().all(|&d| d == 0)")
};
};debug_assert!(zeros.iter().all(|&d| d == 0));
419 *hi /= 10;
420 } else {
421 ::core::panicking::panic("internal error: entered unreachable code");unreachable!();
422 }
423 }
424
425 *dest = product;
426}
427
428pub(crate) fn multiply_scaled_u64_slices_with_prec_into(
430 dest: &mut WithScale<BigDigitVec>,
431 a: WithScale<BigDigitSliceU64>,
432 b: WithScale<BigDigitSliceU64>,
433 prec: NonZeroU64,
434 rounding: NonDigitRoundingData,
435) {
436 let a_base10: BigDigitVecP19 = a.value.into();
437 let b_base10: BigDigitVecP19 = b.value.into();
438
439 let mut product = WithScale::default();
440 multiply_slices_with_prec_into_p19(
441 &mut product,
442 a_base10.as_digit_slice(),
443 b_base10.as_digit_slice(),
444 prec,
445 rounding,
446 );
447
448 dest.scale = a.scale + b.scale + product.scale;
449 dest.value = product.value.into();
450}
451
452fn calculate_partial_product_trailing_zeros(
472 v: &mut BigDigitVecP19,
473 a: BigDigitSliceP19,
474 b: BigDigitSliceP19,
475 product_idx: usize,
476 digits_to_remove: usize,
477) -> bool {
478 type R = RADIX_10p19_u64;
479
480 if digits_to_remove == 0 {
481 return true;
482 }
483
484 if true {
if !(b.len() <= a.len()) {
::core::panicking::panic("assertion failed: b.len() <= a.len()")
};
};debug_assert!(b.len() <= a.len());
485 if true {
if !(digits_to_remove <= v.count_decimal_digits()) {
::core::panicking::panic("assertion failed: digits_to_remove <= v.count_decimal_digits()")
};
};debug_assert!(digits_to_remove <= v.count_decimal_digits());
486
487 let (insig_bd_count, insig_d_count) = R::divmod_digit_count(digits_to_remove);
488 if true {
if !(insig_bd_count > 0 || insig_d_count > 0) {
::core::panicking::panic("assertion failed: insig_bd_count > 0 || insig_d_count > 0")
};
};debug_assert!(insig_bd_count > 0 || insig_d_count > 0);
489
490 let trailing_zeros;
491 let trailing_nines;
492
493 let top_insig_idx;
495
496 match (insig_bd_count, insig_d_count as u8) {
497 (0, 0) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
498 (0, 1) => {
499 return true;
500 }
501 (0, 2) => {
502 return v.digits[0] % 10 == 0;
503 }
504 (0, n) => {
505 let splitter = ten_to_the_u64(n - 1);
506 return v.digits[0] % splitter == 0;
507 }
508 (1, 0) => {
509 let splitter = ten_to_the_u64(R::DIGITS as u8 - 1);
510 return v.digits[0] % splitter == 0;
511 }
512 (1, 1) => {
513 return v.digits[0] == 0;
514 }
515 (i, 1) => {
516 trailing_zeros = v.digits[i - 1] == 0;
519 trailing_nines = v.digits[i - 1] == R::max();
520 top_insig_idx = i - 1;
521 }
522 (i, 0) => {
523 let insig = v.digits[i - 1];
525 let splitter = ten_to_the_u64(R::DIGITS as u8 - 1);
526 let insig_digits = insig % splitter;
527 trailing_zeros = insig_digits == 0
528 && v.iter_le().take(i - 1).all(Zero::is_zero);
529 trailing_nines = insig_digits == splitter - 1;
530 top_insig_idx = i - 2;
531 }
532 (i, n) => {
533 let insig = v.digits[i];
534 let splitter = ten_to_the_u64(n - 1);
535 let insig_digits = insig % splitter;
536 trailing_zeros = insig_digits == 0
537 && v.iter_le().take(i).all(Zero::is_zero);
538 trailing_nines = insig_digits == splitter - 1;
539 top_insig_idx = i - 1;
540 }
541 }
542
543
544 if !trailing_zeros && !trailing_nines {
550 return false;
551 }
552
553 if product_idx == 0 {
554 return trailing_zeros
557 && v.digits[..top_insig_idx].iter().all(|&d| d == 0);
558 }
559
560 if trailing_zeros && (a.digits[0].saturating_mul(b.digits[0])) != 0 {
562 return false;
563 }
564
565 for idx in (0..product_idx).rev() {
566 let a_range;
567 let b_range;
568 if idx < b.len() {
569 a_range = 0..idx + 1;
571 b_range = 0..idx + 1;
572 } else if idx < a.len() {
573 a_range = idx - b.len() + 1..idx + 1;
574 b_range = 0..b.len();
575 } else {
576 a_range = idx - b.len() + 1..a.len();
577 b_range = idx - a.len() + 1..b.len();
578 }
579 if true {
match (&(a_range.end - a_range.start), &(b_range.end - b_range.start)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_eq!(
580 a_range.end - a_range.start,
581 b_range.end - b_range.start,
582 );
583
584 let a_start = a_range.start;
585 let b_start = b_range.start;
586 let a_digits = a.digits[a_range].iter();
587 let b_digits = b.digits[b_range].iter().rev();
588
589 let mut d0 = 0;
590
591 let mut carry = Zero::zero();
592 for (&x, &y) in a_digits.zip(b_digits) {
593 R::carrying_mul_add_inplace(x, y, &mut d0, &mut carry);
594 R::add_carry_into(v.digits.iter_mut(), &mut carry);
595 }
596 if true {
match (&carry, &0) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_eq!(carry, 0);
597
598 let top_insig = v.digits[top_insig_idx];
599 if top_insig != R::max() {
600 return v.least_n_are_zero(top_insig_idx)
602 && a.least_n_are_zero(a_start)
603 && b.least_n_are_zero(b_start);
604 }
605
606 v.digits.copy_within(..top_insig_idx, 1);
609 v.digits[0] = d0;
610 }
611
612 return false;
614}
615
616pub(crate) fn mul_scaled_slices_truncating_into<R, E, EA, EB>(
624 dest: &mut WithScale<DigitVec<R, E>>,
625 a: WithScale<DigitSlice<'_, R, EA>>,
626 b: WithScale<DigitSlice<'_, R, EB>>,
627 prec: u64,
628) -> usize
629where
630 R: RadixType,
631 E: Endianness,
632 EA: Endianness,
633 EB: Endianness,
634{
635 use super::bigdigit::alignment::BigDigitSplitter;
636 use super::bigdigit::alignment::BigDigitSliceSplitterIter;
637 type R = RADIX_10p19_u64;
638
639 if a.value.len() < b.value.len() {
640 return mul_scaled_slices_truncating_into(dest, b, a, prec);
642 }
643
644 let WithScale { value: product, scale: dest_scale } = dest;
645 let WithScale { value: a, scale: a_scale } = a;
646 let WithScale { value: b, scale: b_scale } = b;
647
648 *dest_scale = a_scale + b_scale;
649 product.clear();
650
651 if b.is_all_zeros() || a.is_all_zeros() {
652 return 0;
654 }
655
656 if true {
match (&a.len(), &0) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = ::core::panicking::AssertKind::Ne;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_ne!(a.len(), 0);
657 if true {
match (&b.len(), &0) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = ::core::panicking::AssertKind::Ne;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_ne!(b.len(), 0);
658
659 let max_digit_sum_width = (2.0 * log10(R::max() as f64) + log10(b.len() as f64)).ceil() as usize;
664 let max_bigdigit_sum_width = R::divceil_digit_count(max_digit_sum_width);
665
666 let max_product_size = a.len() + b.len();
667 let max_vector_size = prec as usize + max_bigdigit_sum_width;
668 let bigdigits_to_skip = max_product_size.saturating_sub(max_vector_size);
669
670 *dest_scale -= bigdigits_to_skip as i64;
671
672 multiply_at_product_index(product, a, b, bigdigits_to_skip);
673 product.remove_leading_zeros();
674 let extra_digit_count = product.len().saturating_sub(prec as usize);
675 product.remove_insignificant_digits(extra_digit_count);
676 *dest_scale -= extra_digit_count as i64;
677
678 return bigdigits_to_skip;
679}
680
681
682fn split_u64(x: u64) -> (u64, u64) {
684 x.div_rem(&(1 << 32))
685}
686
687fn mul_split_u64_u64(a: u64, b: u64) -> [u32; 4] {
688 let p = u128::from(a) * u128::from(b);
689 mul_split_u128_to_u32x4(p)
690}
691
692fn mul_split_u128_to_u32x4(n: u128) -> [u32; 4] {
693 [
694 (n >> 0).as_(),
695 (n >> 32).as_(),
696 (n >> 64).as_(),
697 (n >> 96).as_(),
698 ]
699}
700
701#[inline]
703fn _apply_carry_u64(dest: &mut [u32], mut idx: usize, mut carry: u64) {
704 while carry != 0 {
705 idx += 1;
706 let (c, r) = split_u64(dest[idx] as u64 + carry);
707 dest[idx] = r as u32;
708 carry = c;
709 }
710}
711
712pub(crate) fn multiply_2_u64_into_u32(
721 dest: &mut [u32], mut idx: usize, a: u64, b: u64
722) {
723 let [aa0, aa1, aa2, aa3] = mul_split_u64_u64(a, a);
724 let [ab0, ab1, ab2, ab3] = mul_split_u64_u64(a, b);
725 let [bb0, bb1, bb2, bb3] = mul_split_u64_u64(b, b);
726
727 let (carry, r0) = split_u64(dest[idx] as u64 + aa0 as u64);
728 dest[idx] = r0 as u32;
729
730 idx += 1;
731 let (carry, r1) = split_u64(dest[idx] as u64 + carry + aa1 as u64);
732 dest[idx] = r1 as u32;
733
734 idx += 1;
735 let (carry, r2) = split_u64(dest[idx] as u64 + carry + aa2 as u64 + ab0 as u64 * 2);
736 dest[idx] = r2 as u32;
737
738 idx += 1;
739 let (carry, r3) = split_u64(dest[idx] as u64 + carry + aa3 as u64 + ab1 as u64 * 2);
740 dest[idx] = r3 as u32;
741
742 idx += 1;
743 let (carry, r4) = split_u64(dest[idx] as u64 + carry + ab2 as u64 * 2 + bb0 as u64);
744 dest[idx] = r4 as u32;
745
746 idx += 1;
747 let (carry, r5) = split_u64(dest[idx] as u64 + carry + ab3 as u64 * 2 + bb1 as u64);
748 dest[idx] = r5 as u32;
749
750 idx += 1;
751 let (carry, r6) = split_u64(dest[idx] as u64 + carry + bb2 as u64);
752 dest[idx] = r6 as u32;
753
754 idx += 1;
755 let (carry, r7) = split_u64(dest[idx] as u64 + carry + bb3 as u64);
756 dest[idx] = r7 as u32;
757
758 _apply_carry_u64(dest, idx + 1, carry);
759}
760
761pub(crate) fn _multiply_into_4_u64(
763 dest: &mut [u32], idx: usize, a: u64, b: u64, y: u64, z: u64
764) {
765 let [ay0, ay1, ay2, ay3] = mul_split_u64_u64(a, y);
766 let [az0, az1, az2, az3] = mul_split_u64_u64(a, z);
767 let [by0, by1, by2, by3] = mul_split_u64_u64(b, y);
768 let [bz0, bz1, bz2, bz3] = mul_split_u64_u64(b, z);
769
770 let (carry, r0) = split_u64(dest[idx + 0] as u64 + (ay0 as u64 ) * 2);
771 dest[idx + 0] = r0 as u32;
772
773 let (carry, r1) = split_u64(dest[idx + 1] as u64 + carry + (ay1 as u64 ) * 2);
774 dest[idx + 1] = r1 as u32;
775
776 let (carry, r2) = split_u64(dest[idx + 2] as u64 + carry + (ay2 as u64 + az0 as u64 + by0 as u64 ) * 2);
777 dest[idx + 2] = r2 as u32;
778
779 let (carry, r3) = split_u64(dest[idx + 3] as u64 + carry + (ay3 as u64 + az1 as u64 + by1 as u64 ) * 2);
780 dest[idx + 3] = r3 as u32;
781
782 let (carry, r4) = split_u64(dest[idx + 4] as u64 + carry + ( az2 as u64 + by2 as u64 + bz0 as u64) * 2);
783 dest[idx + 4] = r4 as u32;
784
785 let (carry, r5) = split_u64(dest[idx + 5] as u64 + carry + ( az3 as u64 + by3 as u64 + bz1 as u64) * 2);
786 dest[idx + 5] = r5 as u32;
787
788 let (carry, r6) = split_u64(dest[idx + 6] as u64 + carry + ( bz2 as u64) * 2);
789 dest[idx + 6] = r6 as u32;
790
791 let (carry, r7) = split_u64(dest[idx + 7] as u64 + carry + ( bz3 as u64) * 2);
792 dest[idx + 7] = r7 as u32;
793
794 _apply_carry_u64(dest, idx + 8, carry);
795}
796
797pub(crate) fn _multiply_1_u64_into_u32(
799 dest: &mut [u32],
800 mut idx: usize,
801 a: u64
802) {
803 let [a0, a1, a2, a3] = mul_split_u64_u64(a, a);
804
805 let (carry, r0) = split_u64(dest[idx] as u64 + a0 as u64);
806 dest[idx] = r0 as u32;
807
808 idx += 1;
809 let (carry, r1) = split_u64(dest[idx] as u64 + carry + a1 as u64);
810 dest[idx] = r1 as u32;
811
812 idx += 1;
813 let (carry, r2) = split_u64(dest[idx] as u64 + carry + a2 as u64);
814 dest[idx] = r2 as u32;
815
816 idx += 1;
817 let (carry, r3) = split_u64(dest[idx] as u64 + carry + a3 as u64);
818 dest[idx] = r3 as u32;
819
820 _apply_carry_u64(dest, idx + 1, carry);
821}
822
823
824pub(crate) fn _multiply_2_u64_into_u32(
826 dest: &mut [u32],
827 mut idx: usize,
828 a: u64,
829 b: u64,
830) {
831 let [aa0, aa1, aa2, aa3] = mul_split_u64_u64(a, a);
832 let [ab0, ab1, ab2, ab3] = mul_split_u64_u64(a, b);
833 let [bb0, bb1, bb2, bb3] = mul_split_u64_u64(b, b);
834
835 let (carry, r0) = split_u64(dest[idx] as u64 + aa0 as u64);
836 dest[idx] = r0 as u32;
837
838 idx += 1;
839 let (carry, r1) = split_u64(dest[idx] as u64 + carry + aa1 as u64);
840 dest[idx] = r1 as u32;
841
842 idx += 1;
843 let (carry, r2) = split_u64(dest[idx] as u64 + carry + aa2 as u64 + ab0 as u64 * 2);
844 dest[idx] = r2 as u32;
845
846 idx += 1;
847 let (carry, r3) = split_u64(dest[idx] as u64 + carry + aa3 as u64 + ab1 as u64 * 2);
848 dest[idx] = r3 as u32;
849
850 idx += 1;
851 let (carry, r4) = split_u64(dest[idx] as u64 + carry + ab2 as u64 * 2 + bb0 as u64);
852 dest[idx] = r4 as u32;
853
854 idx += 1;
855 let (carry, r5) = split_u64(dest[idx] as u64 + carry + ab3 as u64 * 2 + bb1 as u64);
856 dest[idx] = r5 as u32;
857
858 idx += 1;
859 let (carry, r6) = split_u64(dest[idx] as u64 + carry + bb2 as u64);
860 dest[idx] = r6 as u32;
861
862 idx += 1;
863 let (carry, r7) = split_u64(dest[idx] as u64 + carry + bb3 as u64);
864 dest[idx] = r7 as u32;
865
866 _apply_carry_u64(dest, idx + 1, carry);
867}
868
869
870pub(crate) fn _multiply_3_u64_into_u32(
872 dest: &mut [u32],
873 mut idx: usize,
874 a: u64,
875 b: u64,
876 z: u64,
877) {
878 let [az0, az1, az2, az3] = mul_split_u64_u64(a, z);
879 let [bz0, bz1, bz2, bz3] = mul_split_u64_u64(b, z);
880
881 let (carry, r0) = split_u64(dest[idx] as u64 + (az0 as u64 ) * 2);
882 dest[idx] = r0 as u32;
883
884 idx += 1;
885 let (carry, r1) = split_u64(dest[idx] as u64 + carry + (az1 as u64 ) * 2);
886 dest[idx] = r1 as u32;
887
888 idx += 1;
889 let (carry, r2) = split_u64(dest[idx] as u64 + carry + (az2 as u64 + bz0 as u64) * 2);
890 dest[idx] = r2 as u32;
891
892 idx += 1;
893 let (carry, r3) = split_u64(dest[idx] as u64 + carry + (az3 as u64 + bz1 as u64) * 2);
894 dest[idx] = r3 as u32;
895
896 idx += 1;
897 let (carry, r4) = split_u64(dest[idx] as u64 + carry + ( bz2 as u64) * 2);
898 dest[idx] = r4 as u32;
899
900 idx += 1;
901 let (carry, r5) = split_u64(dest[idx] as u64 + carry + ( bz3 as u64) * 2);
902 dest[idx] = r5 as u32;
903
904 _apply_carry_u64(dest, idx + 1, carry);
905}
906
907
908pub(crate) fn multiply_thrup_spread_into(
910 dest: &mut [u32],
911 idx0: usize,
912 a: u32,
913 b: u32,
914 z: u32,
915) {
916 let a = a as u64;
917 let b = b as u64;
918 let z = z as u64;
919
920 let az = a * z;
921 let bz = b * z;
922
923 let (azh, azl) = split_u64(az);
924 let (bzh, bzl) = split_u64(bz);
925
926 let (carry, r0) = split_u64(dest[idx0 + 0] as u64 + azl * 2);
927 dest[idx0 + 0] = r0 as u32;
928
929 let (carry, r1) = split_u64(dest[idx0 + 1] as u64 + carry + (azh + bzl) * 2);
930 dest[idx0 + 1] = r1 as u32;
931
932 let (mut carry, r2) = split_u64(dest[idx0 + 2] as u64 + carry + bzh * 2);
933 dest[idx0 + 2] = r2 as u32;
934
935 let mut idx = idx0 + 3;
936 while carry != 0 {
937 let (c, overflow) = split_u64(dest[idx] as u64 + carry);
938 dest[idx] = overflow as u32;
939 carry = c;
940 idx += 1;
941 }
942}
943
944pub(crate) fn multiply_thrup_spread_into_wrapped(
947 dest: &mut [u32],
948 idx0: usize,
949 a: u32,
950 b: u32,
951 z: u32,
952) {
953 let a = a as u64;
954 let b = b as u64;
955 let z = z as u64;
956
957 let az = a * z;
958 let bz = b * z;
959
960 let (azh, azl) = split_u64(az);
961 let (bzh, bzl) = split_u64(bz);
962
963 let (carry, r0) = split_u64(dest[idx0 + 0] as u64 + azl * 2);
964 dest[idx0 + 0] = r0 as u32;
965
966 let (carry, r1) = split_u64(dest[idx0 + 1] as u64 + carry + (azh + bzl) * 2);
967 dest[idx0 + 1] = r1 as u32;
968
969 let (mut carry, r2) = split_u64(dest[idx0 + 2] as u64 + carry + bzh * 2);
970 dest[idx0 + 2] = r2 as u32;
971
972 let mut idx = idx0 + 3;
973 while carry != 0 {
974 let (c, overflow) = split_u64(dest[idx] as u64 + carry);
975 dest[idx] = overflow as u32;
976 carry = c;
977 idx += 1;
978 }
979}
980
981pub(crate) fn multiply_quad_spread_into(
990 dest: &mut [u32],
991 idx0: usize,
992 a: u32,
993 b: u32,
994 y: u32,
995 z: u32,
996) {
997 let ay = a as u64 * y as u64;
998 let az = a as u64 * z as u64;
999
1000 let by = b as u64 * y as u64;
1001 let bz = b as u64 * z as u64;
1002
1003 let (ayh, ayl) = split_u64(ay);
1004 let (azh, azl) = split_u64(az);
1005 let (byh, byl) = split_u64(by);
1006 let (bzh, bzl) = split_u64(bz);
1007
1008 let (carry, r0) = split_u64(dest[idx0 + 0] as u64 + ayl * 2);
1009 dest[idx0 + 0] = r0 as u32;
1010
1011 let (carry, r1) = split_u64(dest[idx0 + 1] as u64 + carry + (ayh + azl + byl) * 2);
1012 dest[idx0 + 1] = r1 as u32;
1013
1014 let (carry, r2) = split_u64(dest[idx0 + 2] as u64 + carry + (azh + byh + bzl) * 2);
1015 dest[idx0 + 2] = r2 as u32;
1016
1017 let (mut carry, r3) = split_u64(dest[idx0 + 3] as u64 + carry + bzh * 2);
1018 dest[idx0 + 3] = r3 as u32;
1019
1020 let mut idx = idx0 + 4;
1021 while carry != 0 {
1022 let (c, overflow) = split_u64(dest[idx] as u64 + carry);
1023 dest[idx] = overflow as u32;
1024 carry = c;
1025 idx += 1;
1026 }
1027}
1028
1029pub(crate) fn multiply_quad_spread_into_wrapping(
1032 dest: &mut [u32],
1033 idx: usize,
1034 a: u32,
1035 b: u32,
1036 y: u32,
1037 z: u32,
1038) {
1039 let ay = a as u64 * y as u64;
1040 let az = a as u64 * z as u64;
1041
1042 let by = b as u64 * y as u64;
1043 let bz = b as u64 * z as u64;
1044
1045 let (ayh, ayl) = split_u64(ay);
1046 let (azh, azl) = split_u64(az);
1047 let (byh, byl) = split_u64(by);
1048 let (bzh, bzl) = split_u64(bz);
1049
1050 let wrap = dest.len();
1051 let mut idx = idx % wrap;
1052
1053 let (carry, r0) = split_u64(dest[idx] as u64 + ayl * 2);
1054 dest[idx] = r0 as u32;
1055
1056 idx = (idx + 1) % wrap;
1057 let (carry, r1) = split_u64(dest[idx] as u64 + carry + (ayh + azl + byl) * 2);
1058 dest[idx] = r1 as u32;
1059
1060 idx = (idx + 1) % wrap;
1061 let (carry, r2) = split_u64(dest[idx] as u64 + carry + (azh + byh + bzl) * 2);
1062 dest[idx] = r2 as u32;
1063
1064 idx = (idx + 1) % wrap;
1065 let (mut carry, r3) = split_u64(dest[idx] as u64 + carry + bzh * 2);
1066 dest[idx] = r3 as u32;
1067
1068 while carry != 0 {
1069 idx = (idx + 1) % wrap;
1070 let (c, overflow) = split_u64(dest[idx] as u64 + carry);
1071 dest[idx] = overflow as u32;
1072 carry = c;
1073 }
1074}
1075
1076#[cfg(test)]
1077mod test {
1078 use super::*;
1079 include!("multiplication.tests.rs");
1080}