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
32#[inline(always)]
34pub(crate) fn mulassign_bigdecimal_ref<'a>(
35 dest: &mut BigDecimal,
36 rhs: impl Into<BigDecimalRef<'a>>,
37) {
38 impl_mulassign_bigdecimal_ref(dest, rhs.into());
39}
40
41pub(crate) fn impl_mulassign_bigdecimal_ref(
43 dest: &mut BigDecimal,
44 rhs: BigDecimalRef,
45) {
46 dest.scale += rhs.scale;
47 mulassign_bigint_biguint_ref(&mut dest.int_val, rhs.digits);
48 if rhs.sign == Sign::Minus {
49 dest.int_val *= -1;
50 }
51}
52
53pub(crate) fn mulassign_bigint_biguint_ref(
58 dest: &mut BigInt,
59 n: &BigUint,
60) {
61 match n.to_u128() {
62 Some(n) => {
63 dest.mul_assign(n);
64 }
65 None => {
66 dest.mul_assign(BigInt::from(n.clone()));
67 }
68 }
69}
70
71pub(crate) fn multiply_decimals_with_context<'a>(
73 dest: &mut BigDecimal,
74 a: impl Into<BigDecimalRef<'a>>,
75 b: impl Into<BigDecimalRef<'a>>,
76 ctx: &Context,
77) {
78 let a = a.into();
79 let b = b.into();
80
81 impl_multiply_decimals_with_context(dest, a, b, ctx);
82}
83
84pub fn impl_multiply_decimals_with_context(
86 dest: &mut BigDecimal,
87 a: BigDecimalRef,
88 b: BigDecimalRef,
89 ctx: &Context,
90) {
91 if a.is_zero() || b.is_zero() {
92 *dest = BigDecimal::zero();
93 return;
94 }
95
96 let sign = a.sign() * b.sign();
97 let rounding_data = NonDigitRoundingData {
98 sign: sign,
99 mode: ctx.rounding_mode(),
100 };
101
102 let a_uint = a.digits;
103 let b_uint = b.digits;
104
105 match (a, b.is_one_quickcheck(), b, a.is_one_quickcheck()) {
106 (x, Some(true), _, _) | (_, _, x, Some(true)) => {
107 let WithScale {
108 value: rounded_uint,
109 scale: rounded_scale,
110 } = rounding_data.round_biguint_to_prec(x.digits.clone(), ctx.precision());
111
112 dest.scale = x.scale + rounded_scale;
113 dest.int_val = BigInt::from_biguint(sign, rounded_uint);
114 return;
115 }
116 _ => {}
117 }
118
119 if let (Some(x), Some(y)) = (a_uint.to_u64(), b_uint.to_u64()) {
120 multiply_scaled_u64_into_decimal(
121 dest,
122 WithScale { value: x, scale: a.scale },
123 WithScale { value: y, scale: b.scale },
124 ctx.precision(),
125 rounding_data,
126 );
127 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);
128 return;
129 }
130
131 let a_vec = BigDigitVec::from(a_uint);
132 let b_vec = BigDigitVec::from(b_uint);
133
134 let digit_vec = BigDigitVec::new();
135 let mut digit_vec_scale = WithScale::from((digit_vec, 0));
136
137 multiply_scaled_u64_slices_with_prec_into(
138 &mut digit_vec_scale,
139 WithScale { value: a_vec.as_digit_slice(), scale: a.scale },
140 WithScale { value: b_vec.as_digit_slice(), scale: b.scale },
141 ctx.precision(),
142 rounding_data,
143 );
144
145 dest.int_val = BigInt::from_biguint(sign, digit_vec_scale.value.into());
146 dest.scale = digit_vec_scale.scale;
147}
148
149pub(crate) fn multiply_scaled_u64_into_decimal(
150 dest: &mut BigDecimal,
151 a: WithScale<u64>,
152 b: WithScale<u64>,
153 prec: NonZeroU64,
154 rounding_data: NonDigitRoundingData,
155) {
156 use crate::arithmetic::decimal::count_digits_u128;
157
158 let mut product = a.value as u128 * b.value as u128;
159 let digit_count = count_digits_u128(product) as u64;
160
161 let mut digits_to_remove = digit_count.saturating_sub(prec.get()) as u32;
162
163 if digits_to_remove == 0 {
164 dest.int_val = BigInt::from_biguint(rounding_data.sign, product.into());
165 dest.scale = a.scale + b.scale;
166 return;
167 }
168
169 let shifter = 10u128.pow(digits_to_remove - 1);
170 let (hi, trailing) = product.div_rem(&shifter);
171 let (shifted_product, insig_digit) = hi.div_rem(&10);
172 let sig_digit = (shifted_product % 10) as u8;
173
174 let rounded_digit = rounding_data.round_pair(
175 (sig_digit, insig_digit as u8),
176 trailing == 0,
177 );
178
179 product = shifted_product - sig_digit as u128 + rounded_digit as u128;
180
181 if rounded_digit >= 10 {
182 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);
183
184 let old_digit_count = digit_count - digits_to_remove as u64;
185 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);
186
187 let rounded_digit_count = count_digits_u128(product) as u64;
188 if old_digit_count != rounded_digit_count {
189 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);
190 product /= 10;
191 digits_to_remove += 1;
192 }
193 }
194
195 let digit_array = mul_split_u128_to_u32x4(product);
196 dest.int_val.assign_from_slice(rounding_data.sign, &digit_array);
197
198 dest.scale = a.scale + b.scale - digits_to_remove as i64;
199}
200
201pub(crate) fn multiply_at_product_index<R, E, EA, EB>(
216 dest: &mut DigitVec<R, E>,
217 a: DigitSlice<R, EA>,
218 b: DigitSlice<R, EB>,
219 idx: usize,
220) where
221 R: RadixType,
222 E: Endianness,
223 EA: Endianness,
224 EB: Endianness,
225{
226 if true {
if !(b.len() <= a.len()) {
::core::panicking::panic("assertion failed: b.len() <= a.len()")
};
};debug_assert!(b.len() <= a.len());
227
228 dest.resize((a.len() + b.len()).saturating_sub(idx));
229
230 let b_idx_min = idx.saturating_sub(a.len() - 1);
231
232 for (b_idx, &x) in b.iter_le().enumerate().skip(b_idx_min).rev() {
233 let a_idx_min = idx.saturating_sub(b_idx);
234 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());
235
236 let dest_idx = a_idx_min + b_idx - idx;
237
238 let mut dest_digits = dest.iter_le_mut().skip(dest_idx);
239 let mut carry = Zero::zero();
240 for &y in a.iter_le().skip(a_idx_min) {
241 R::carrying_mul_add_inplace(
242 x, y, dest_digits.next().unwrap(), &mut carry
243 );
244 }
245 R::add_carry_into(dest_digits, &mut carry);
246 if !carry.is_zero() {
247 dest.push_significant_digit(carry);
248 }
249 }
250}
251
252
253pub(crate) fn multiply_at_idx_into<R: RadixType>(
254 dest: &mut DigitVec<R, LittleEndian>,
255 a: DigitSlice<R, LittleEndian>,
256 b: DigitSlice<R, LittleEndian>,
257 idx: usize,
258) {
259 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);
260 for (ia, &da) in a.digits.iter().enumerate() {
261 if da.is_zero() {
262 continue;
263 }
264 let mut carry = Zero::zero();
265 for (&db, result) in b.digits.iter().zip(dest.digits.iter_mut().skip(idx + ia)) {
266 R::carrying_mul_add_inplace(da, db, result, &mut carry);
267 }
268 dest.add_value_at(idx + ia + b.len(), carry);
269 }
270}
271
272pub(crate) fn multiply_big_int_with_ctx(a: &BigInt, b: &BigInt, ctx: Context) -> WithScale<BigInt> {
273 let sign = a.sign() * b.sign();
274 let rounding_data = NonDigitRoundingData {
276 sign: sign,
277 mode: ctx.rounding_mode(),
278 };
279
280 if a.bits() + b.bits() < BASE2_BIGINT_MUL_THRESHOLD {
282 return ctx.round_bigint(a * b);
283 }
284
285 let mut tmp = Vec::new();
286 let a_p19_vec = BigDigitVecP19::from_biguint_using_tmp(a.magnitude(), &mut tmp);
287 let b_p19_vec = BigDigitVecP19::from_biguint_using_tmp(b.magnitude(), &mut tmp);
288
289 let mut result = WithScale::default();
290 multiply_slices_with_prec_into_p19(
291 &mut result,
292 a_p19_vec.as_digit_slice(),
293 b_p19_vec.as_digit_slice(),
294 ctx.precision(),
295 rounding_data
296 );
297
298 WithScale {
299 scale: result.scale,
300 value: result.value.into_bigint(sign),
301 }
302}
303
304pub(crate) fn multiply_slices_with_prec_into_p19(
312 dest: &mut WithScale<BigDigitVecP19>,
313 a: BigDigitSliceP19,
314 b: BigDigitSliceP19,
315 prec: NonZeroU64,
316 rounding: NonDigitRoundingData
317) {
318 multiply_slices_with_prec_into_p19_z(dest, a, b, prec, rounding, true)
319}
320
321
322pub(crate) fn multiply_slices_with_prec_into_p19_z(
330 dest: &mut WithScale<BigDigitVecP19>,
331 a: BigDigitSliceP19,
332 b: BigDigitSliceP19,
333 prec: NonZeroU64,
334 rounding: NonDigitRoundingData,
335 assume_trailing_zeros: bool,
336) {
337 use super::bigdigit::alignment::BigDigitSplitter;
338 use super::bigdigit::alignment::BigDigitSliceSplitterIter;
339 type R = RADIX_10p19_u64;
340
341 if a.len() < b.len() {
342 return multiply_slices_with_prec_into_p19_z(dest, b, a, prec, rounding, assume_trailing_zeros);
344 }
345
346 dest.value.clear();
347
348 if b.is_all_zeros() || a.is_all_zeros() {
349 return;
351 }
352
353 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);
354 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);
355
356 let WithScale { value: dest, scale: result_scale } = dest;
357
358 let pessimistic_product_digit_count = (a.len() + b.len() - 2) * R::DIGITS + 1;
360
361 let max_digit_sum_width = (2.0 * log10(R::max() as f64) + log10(b.len() as f64)).ceil() as usize;
366 let max_bigdigit_sum_width = R::divceil_digit_count(max_digit_sum_width);
367 let digits_to_skip = pessimistic_product_digit_count.saturating_sub(prec.get() as usize + 1);
369 let bigdigits_to_skip = R::divceil_digit_count(digits_to_skip)
370 .saturating_sub(max_bigdigit_sum_width);
371
372 let a_start;
373 let b_start;
374 if bigdigits_to_skip == 0 {
375 a_start = 0;
377 b_start = 0;
378 } else {
379 a_start = bigdigits_to_skip.saturating_sub(b.len());
382 b_start = bigdigits_to_skip.saturating_sub(a.len());
383 }
384
385 let a_sig = a.trim_insignificant(a_start);
386 let b_sig = b.trim_insignificant(b_start);
387
388 let a_sig_digit_count = a_sig.count_decimal_digits();
389 let b_sig_digit_count = b_sig.count_decimal_digits();
390
391 let max_sigproduct_bigdigit_count = R::divceil_digit_count(a_sig_digit_count + b_sig_digit_count + 1);
393 let mut product =
394 BigDigitVecP19::with_capacity(max_sigproduct_bigdigit_count + max_bigdigit_sum_width + 1);
395
396 *result_scale -= (R::DIGITS * bigdigits_to_skip) as i64;
397
398 multiply_at_product_index(&mut product, a, b, bigdigits_to_skip);
399 product.remove_leading_zeros();
400
401 let product_digit_count = product.count_decimal_digits();
402
403 let digits_to_remove = product_digit_count.saturating_sub(prec.get() as usize);
405 if digits_to_remove == 0 {
406 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);
407 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);
408 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);
409
410 *dest = product;
412 return;
413 }
414
415 *result_scale -= digits_to_remove as i64;
417
418 let trailing_zeros = assume_trailing_zeros && calculate_partial_product_trailing_zeros(
422 &mut product, a, b, bigdigits_to_skip, digits_to_remove
423 );
424
425 let insig_digit = product.shift_n_digits_returning_high(digits_to_remove);
427 let sig_digit = (product.digits[0] % 10) as u8;
428
429 let insig_rounding_data = InsigData {
430 rounding_data: rounding,
431 digit: insig_digit,
432 trailing_zeros,
433 };
434
435 let rounded_digit = insig_rounding_data.round_digit(sig_digit);
436
437 let mut carry = rounded_digit as u64;
438
439 product.digits[0] -= sig_digit as u64;
440
441 R::add_carry_into_slice(
442 &mut product.digits, &mut carry
443 );
444
445 if carry != 0 {
446 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));
447 *result_scale -= 1;
448 *product.digits.last_mut().unwrap() = (R::RADIX as u64) / 10;
449 }
450
451 if rounded_digit == 10 && product.count_decimal_digits() != prec.get() as usize {
452 *result_scale -= 1;
453
454 if let Some((hi, zeros)) = product.digits.split_last_mut() {
455 if true {
if !(*hi >= 10) {
::core::panicking::panic("assertion failed: *hi >= 10")
};
};debug_assert!(*hi >= 10);
456 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));
457 *hi /= 10;
458 } else {
459 ::core::panicking::panic("internal error: entered unreachable code");unreachable!();
460 }
461 }
462
463 *dest = product;
464}
465
466pub(crate) fn multiply_scaled_u64_slices_with_prec_into(
468 dest: &mut WithScale<BigDigitVec>,
469 a: WithScale<BigDigitSliceU64>,
470 b: WithScale<BigDigitSliceU64>,
471 prec: NonZeroU64,
472 rounding: NonDigitRoundingData,
473) {
474 let a_base10: BigDigitVecP19 = a.value.into();
475 let b_base10: BigDigitVecP19 = b.value.into();
476
477 let mut product = WithScale::default();
478 multiply_slices_with_prec_into_p19(
479 &mut product,
480 a_base10.as_digit_slice(),
481 b_base10.as_digit_slice(),
482 prec,
483 rounding,
484 );
485
486 dest.scale = a.scale + b.scale + product.scale;
487 dest.value = product.value.into();
488}
489
490fn calculate_partial_product_trailing_zeros(
510 v: &mut BigDigitVecP19,
511 a: BigDigitSliceP19,
512 b: BigDigitSliceP19,
513 product_idx: usize,
514 digits_to_remove: usize,
515) -> bool {
516 type R = RADIX_10p19_u64;
517
518 if digits_to_remove == 0 {
519 return true;
520 }
521
522 if true {
if !(b.len() <= a.len()) {
::core::panicking::panic("assertion failed: b.len() <= a.len()")
};
};debug_assert!(b.len() <= a.len());
523 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());
524
525 let (insig_bd_count, insig_d_count) = R::divmod_digit_count(digits_to_remove);
526 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);
527
528 let trailing_zeros;
529 let trailing_nines;
530
531 let top_insig_idx;
533
534 match (insig_bd_count, insig_d_count as u8) {
535 (0, 0) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
536 (0, 1) => {
537 return true;
538 }
539 (0, 2) => {
540 return v.digits[0] % 10 == 0;
541 }
542 (0, n) => {
543 let splitter = ten_to_the_u64(n - 1);
544 return v.digits[0] % splitter == 0;
545 }
546 (1, 0) => {
547 let splitter = ten_to_the_u64(R::DIGITS as u8 - 1);
548 return v.digits[0] % splitter == 0;
549 }
550 (1, 1) => {
551 return v.digits[0] == 0;
552 }
553 (i, 1) => {
554 trailing_zeros = v.digits[i - 1] == 0;
557 trailing_nines = v.digits[i - 1] == R::max();
558 top_insig_idx = i - 1;
559 }
560 (i, 0) => {
561 let insig = v.digits[i - 1];
563 let splitter = ten_to_the_u64(R::DIGITS as u8 - 1);
564 let insig_digits = insig % splitter;
565 trailing_zeros = insig_digits == 0
566 && v.iter_le().take(i - 1).all(Zero::is_zero);
567 trailing_nines = insig_digits == splitter - 1;
568 top_insig_idx = i - 2;
569 }
570 (i, n) => {
571 let insig = v.digits[i];
572 let splitter = ten_to_the_u64(n - 1);
573 let insig_digits = insig % splitter;
574 trailing_zeros = insig_digits == 0
575 && v.iter_le().take(i).all(Zero::is_zero);
576 trailing_nines = insig_digits == splitter - 1;
577 top_insig_idx = i - 1;
578 }
579 }
580
581
582 if !trailing_zeros && !trailing_nines {
588 return false;
589 }
590
591 if product_idx == 0 {
592 return trailing_zeros
595 && v.digits[..top_insig_idx].iter().all(|&d| d == 0);
596 }
597
598 if trailing_zeros && (a.digits[0].saturating_mul(b.digits[0])) != 0 {
600 return false;
601 }
602
603 for idx in (0..product_idx).rev() {
604 let a_range;
605 let b_range;
606 if idx < b.len() {
607 a_range = 0..idx + 1;
609 b_range = 0..idx + 1;
610 } else if idx < a.len() {
611 a_range = idx - b.len() + 1..idx + 1;
612 b_range = 0..b.len();
613 } else {
614 a_range = idx - b.len() + 1..a.len();
615 b_range = idx - a.len() + 1..b.len();
616 }
617 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!(
618 a_range.end - a_range.start,
619 b_range.end - b_range.start,
620 );
621
622 let a_start = a_range.start;
623 let b_start = b_range.start;
624 let a_digits = a.digits[a_range].iter();
625 let b_digits = b.digits[b_range].iter().rev();
626
627 let mut d0 = 0;
628
629 let mut carry = Zero::zero();
630 for (&x, &y) in a_digits.zip(b_digits) {
631 R::carrying_mul_add_inplace(x, y, &mut d0, &mut carry);
632 R::add_carry_into(v.digits.iter_mut(), &mut carry);
633 }
634 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);
635
636 let top_insig = v.digits[top_insig_idx];
637 if top_insig != R::max() {
638 return v.least_n_are_zero(top_insig_idx)
640 && a.least_n_are_zero(a_start)
641 && b.least_n_are_zero(b_start);
642 }
643
644 v.digits.copy_within(..top_insig_idx, 1);
647 v.digits[0] = d0;
648 }
649
650 return false;
652}
653
654pub(crate) fn mul_scaled_slices_truncating_into<R, E, EA, EB>(
662 dest: &mut WithScale<DigitVec<R, E>>,
663 a: WithScale<DigitSlice<'_, R, EA>>,
664 b: WithScale<DigitSlice<'_, R, EB>>,
665 prec: u64,
666) -> usize
667where
668 R: RadixType,
669 E: Endianness,
670 EA: Endianness,
671 EB: Endianness,
672{
673 use super::bigdigit::alignment::BigDigitSplitter;
674 use super::bigdigit::alignment::BigDigitSliceSplitterIter;
675 type R = RADIX_10p19_u64;
676
677 if a.value.len() < b.value.len() {
678 return mul_scaled_slices_truncating_into(dest, b, a, prec);
680 }
681
682 let WithScale { value: product, scale: dest_scale } = dest;
683 let WithScale { value: a, scale: a_scale } = a;
684 let WithScale { value: b, scale: b_scale } = b;
685
686 *dest_scale = a_scale + b_scale;
687 product.clear();
688
689 if b.is_all_zeros() || a.is_all_zeros() {
690 return 0;
692 }
693
694 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);
695 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);
696
697 let max_digit_sum_width = (2.0 * log10(R::max() as f64) + log10(b.len() as f64)).ceil() as usize;
702 let max_bigdigit_sum_width = R::divceil_digit_count(max_digit_sum_width);
703
704 let max_product_size = a.len() + b.len();
705 let max_vector_size = prec as usize + max_bigdigit_sum_width;
706 let bigdigits_to_skip = max_product_size.saturating_sub(max_vector_size);
707
708 *dest_scale -= bigdigits_to_skip as i64;
709
710 multiply_at_product_index(product, a, b, bigdigits_to_skip);
711 product.remove_leading_zeros();
712 let extra_digit_count = product.len().saturating_sub(prec as usize);
713 product.remove_insignificant_digits(extra_digit_count);
714 *dest_scale -= extra_digit_count as i64;
715
716 return bigdigits_to_skip;
717}
718
719
720fn split_u64(x: u64) -> (u64, u64) {
722 x.div_rem(&(1 << 32))
723}
724
725fn mul_split_u64_u64(a: u64, b: u64) -> [u32; 4] {
726 let p = u128::from(a) * u128::from(b);
727 mul_split_u128_to_u32x4(p)
728}
729
730fn mul_split_u128_to_u32x4(n: u128) -> [u32; 4] {
731 [
732 (n >> 0).as_(),
733 (n >> 32).as_(),
734 (n >> 64).as_(),
735 (n >> 96).as_(),
736 ]
737}
738
739#[inline]
741fn _apply_carry_u64(dest: &mut [u32], mut idx: usize, mut carry: u64) {
742 while carry != 0 {
743 idx += 1;
744 let (c, r) = split_u64(dest[idx] as u64 + carry);
745 dest[idx] = r as u32;
746 carry = c;
747 }
748}
749
750pub(crate) fn multiply_2_u64_into_u32(
759 dest: &mut [u32], mut idx: usize, a: u64, b: u64
760) {
761 let [aa0, aa1, aa2, aa3] = mul_split_u64_u64(a, a);
762 let [ab0, ab1, ab2, ab3] = mul_split_u64_u64(a, b);
763 let [bb0, bb1, bb2, bb3] = mul_split_u64_u64(b, b);
764
765 let (carry, r0) = split_u64(dest[idx] as u64 + aa0 as u64);
766 dest[idx] = r0 as u32;
767
768 idx += 1;
769 let (carry, r1) = split_u64(dest[idx] as u64 + carry + aa1 as u64);
770 dest[idx] = r1 as u32;
771
772 idx += 1;
773 let (carry, r2) = split_u64(dest[idx] as u64 + carry + aa2 as u64 + ab0 as u64 * 2);
774 dest[idx] = r2 as u32;
775
776 idx += 1;
777 let (carry, r3) = split_u64(dest[idx] as u64 + carry + aa3 as u64 + ab1 as u64 * 2);
778 dest[idx] = r3 as u32;
779
780 idx += 1;
781 let (carry, r4) = split_u64(dest[idx] as u64 + carry + ab2 as u64 * 2 + bb0 as u64);
782 dest[idx] = r4 as u32;
783
784 idx += 1;
785 let (carry, r5) = split_u64(dest[idx] as u64 + carry + ab3 as u64 * 2 + bb1 as u64);
786 dest[idx] = r5 as u32;
787
788 idx += 1;
789 let (carry, r6) = split_u64(dest[idx] as u64 + carry + bb2 as u64);
790 dest[idx] = r6 as u32;
791
792 idx += 1;
793 let (carry, r7) = split_u64(dest[idx] as u64 + carry + bb3 as u64);
794 dest[idx] = r7 as u32;
795
796 _apply_carry_u64(dest, idx + 1, carry);
797}
798
799pub(crate) fn _multiply_into_4_u64(
801 dest: &mut [u32], idx: usize, a: u64, b: u64, y: u64, z: u64
802) {
803 let [ay0, ay1, ay2, ay3] = mul_split_u64_u64(a, y);
804 let [az0, az1, az2, az3] = mul_split_u64_u64(a, z);
805 let [by0, by1, by2, by3] = mul_split_u64_u64(b, y);
806 let [bz0, bz1, bz2, bz3] = mul_split_u64_u64(b, z);
807
808 let (carry, r0) = split_u64(dest[idx + 0] as u64 + (ay0 as u64 ) * 2);
809 dest[idx + 0] = r0 as u32;
810
811 let (carry, r1) = split_u64(dest[idx + 1] as u64 + carry + (ay1 as u64 ) * 2);
812 dest[idx + 1] = r1 as u32;
813
814 let (carry, r2) = split_u64(dest[idx + 2] as u64 + carry + (ay2 as u64 + az0 as u64 + by0 as u64 ) * 2);
815 dest[idx + 2] = r2 as u32;
816
817 let (carry, r3) = split_u64(dest[idx + 3] as u64 + carry + (ay3 as u64 + az1 as u64 + by1 as u64 ) * 2);
818 dest[idx + 3] = r3 as u32;
819
820 let (carry, r4) = split_u64(dest[idx + 4] as u64 + carry + ( az2 as u64 + by2 as u64 + bz0 as u64) * 2);
821 dest[idx + 4] = r4 as u32;
822
823 let (carry, r5) = split_u64(dest[idx + 5] as u64 + carry + ( az3 as u64 + by3 as u64 + bz1 as u64) * 2);
824 dest[idx + 5] = r5 as u32;
825
826 let (carry, r6) = split_u64(dest[idx + 6] as u64 + carry + ( bz2 as u64) * 2);
827 dest[idx + 6] = r6 as u32;
828
829 let (carry, r7) = split_u64(dest[idx + 7] as u64 + carry + ( bz3 as u64) * 2);
830 dest[idx + 7] = r7 as u32;
831
832 _apply_carry_u64(dest, idx + 8, carry);
833}
834
835pub(crate) fn _multiply_1_u64_into_u32(
837 dest: &mut [u32],
838 mut idx: usize,
839 a: u64
840) {
841 let [a0, a1, a2, a3] = mul_split_u64_u64(a, a);
842
843 let (carry, r0) = split_u64(dest[idx] as u64 + a0 as u64);
844 dest[idx] = r0 as u32;
845
846 idx += 1;
847 let (carry, r1) = split_u64(dest[idx] as u64 + carry + a1 as u64);
848 dest[idx] = r1 as u32;
849
850 idx += 1;
851 let (carry, r2) = split_u64(dest[idx] as u64 + carry + a2 as u64);
852 dest[idx] = r2 as u32;
853
854 idx += 1;
855 let (carry, r3) = split_u64(dest[idx] as u64 + carry + a3 as u64);
856 dest[idx] = r3 as u32;
857
858 _apply_carry_u64(dest, idx + 1, carry);
859}
860
861
862pub(crate) fn _multiply_2_u64_into_u32(
864 dest: &mut [u32],
865 mut idx: usize,
866 a: u64,
867 b: u64,
868) {
869 let [aa0, aa1, aa2, aa3] = mul_split_u64_u64(a, a);
870 let [ab0, ab1, ab2, ab3] = mul_split_u64_u64(a, b);
871 let [bb0, bb1, bb2, bb3] = mul_split_u64_u64(b, b);
872
873 let (carry, r0) = split_u64(dest[idx] as u64 + aa0 as u64);
874 dest[idx] = r0 as u32;
875
876 idx += 1;
877 let (carry, r1) = split_u64(dest[idx] as u64 + carry + aa1 as u64);
878 dest[idx] = r1 as u32;
879
880 idx += 1;
881 let (carry, r2) = split_u64(dest[idx] as u64 + carry + aa2 as u64 + ab0 as u64 * 2);
882 dest[idx] = r2 as u32;
883
884 idx += 1;
885 let (carry, r3) = split_u64(dest[idx] as u64 + carry + aa3 as u64 + ab1 as u64 * 2);
886 dest[idx] = r3 as u32;
887
888 idx += 1;
889 let (carry, r4) = split_u64(dest[idx] as u64 + carry + ab2 as u64 * 2 + bb0 as u64);
890 dest[idx] = r4 as u32;
891
892 idx += 1;
893 let (carry, r5) = split_u64(dest[idx] as u64 + carry + ab3 as u64 * 2 + bb1 as u64);
894 dest[idx] = r5 as u32;
895
896 idx += 1;
897 let (carry, r6) = split_u64(dest[idx] as u64 + carry + bb2 as u64);
898 dest[idx] = r6 as u32;
899
900 idx += 1;
901 let (carry, r7) = split_u64(dest[idx] as u64 + carry + bb3 as u64);
902 dest[idx] = r7 as u32;
903
904 _apply_carry_u64(dest, idx + 1, carry);
905}
906
907
908pub(crate) fn _multiply_3_u64_into_u32(
910 dest: &mut [u32],
911 mut idx: usize,
912 a: u64,
913 b: u64,
914 z: u64,
915) {
916 let [az0, az1, az2, az3] = mul_split_u64_u64(a, z);
917 let [bz0, bz1, bz2, bz3] = mul_split_u64_u64(b, z);
918
919 let (carry, r0) = split_u64(dest[idx] as u64 + (az0 as u64 ) * 2);
920 dest[idx] = r0 as u32;
921
922 idx += 1;
923 let (carry, r1) = split_u64(dest[idx] as u64 + carry + (az1 as u64 ) * 2);
924 dest[idx] = r1 as u32;
925
926 idx += 1;
927 let (carry, r2) = split_u64(dest[idx] as u64 + carry + (az2 as u64 + bz0 as u64) * 2);
928 dest[idx] = r2 as u32;
929
930 idx += 1;
931 let (carry, r3) = split_u64(dest[idx] as u64 + carry + (az3 as u64 + bz1 as u64) * 2);
932 dest[idx] = r3 as u32;
933
934 idx += 1;
935 let (carry, r4) = split_u64(dest[idx] as u64 + carry + ( bz2 as u64) * 2);
936 dest[idx] = r4 as u32;
937
938 idx += 1;
939 let (carry, r5) = split_u64(dest[idx] as u64 + carry + ( bz3 as u64) * 2);
940 dest[idx] = r5 as u32;
941
942 _apply_carry_u64(dest, idx + 1, carry);
943}
944
945
946pub(crate) fn multiply_thrup_spread_into(
948 dest: &mut [u32],
949 idx0: usize,
950 a: u32,
951 b: u32,
952 z: u32,
953) {
954 let a = a as u64;
955 let b = b as u64;
956 let z = z as u64;
957
958 let az = a * z;
959 let bz = b * z;
960
961 let (azh, azl) = split_u64(az);
962 let (bzh, bzl) = split_u64(bz);
963
964 let (carry, r0) = split_u64(dest[idx0 + 0] as u64 + azl * 2);
965 dest[idx0 + 0] = r0 as u32;
966
967 let (carry, r1) = split_u64(dest[idx0 + 1] as u64 + carry + (azh + bzl) * 2);
968 dest[idx0 + 1] = r1 as u32;
969
970 let (mut carry, r2) = split_u64(dest[idx0 + 2] as u64 + carry + bzh * 2);
971 dest[idx0 + 2] = r2 as u32;
972
973 let mut idx = idx0 + 3;
974 while carry != 0 {
975 let (c, overflow) = split_u64(dest[idx] as u64 + carry);
976 dest[idx] = overflow as u32;
977 carry = c;
978 idx += 1;
979 }
980}
981
982pub(crate) fn multiply_thrup_spread_into_wrapped(
985 dest: &mut [u32],
986 idx0: usize,
987 a: u32,
988 b: u32,
989 z: u32,
990) {
991 let a = a as u64;
992 let b = b as u64;
993 let z = z as u64;
994
995 let az = a * z;
996 let bz = b * z;
997
998 let (azh, azl) = split_u64(az);
999 let (bzh, bzl) = split_u64(bz);
1000
1001 let (carry, r0) = split_u64(dest[idx0 + 0] as u64 + azl * 2);
1002 dest[idx0 + 0] = r0 as u32;
1003
1004 let (carry, r1) = split_u64(dest[idx0 + 1] as u64 + carry + (azh + bzl) * 2);
1005 dest[idx0 + 1] = r1 as u32;
1006
1007 let (mut carry, r2) = split_u64(dest[idx0 + 2] as u64 + carry + bzh * 2);
1008 dest[idx0 + 2] = r2 as u32;
1009
1010 let mut idx = idx0 + 3;
1011 while carry != 0 {
1012 let (c, overflow) = split_u64(dest[idx] as u64 + carry);
1013 dest[idx] = overflow as u32;
1014 carry = c;
1015 idx += 1;
1016 }
1017}
1018
1019pub(crate) fn multiply_quad_spread_into(
1028 dest: &mut [u32],
1029 idx0: usize,
1030 a: u32,
1031 b: u32,
1032 y: u32,
1033 z: u32,
1034) {
1035 let ay = a as u64 * y as u64;
1036 let az = a as u64 * z as u64;
1037
1038 let by = b as u64 * y as u64;
1039 let bz = b as u64 * z as u64;
1040
1041 let (ayh, ayl) = split_u64(ay);
1042 let (azh, azl) = split_u64(az);
1043 let (byh, byl) = split_u64(by);
1044 let (bzh, bzl) = split_u64(bz);
1045
1046 let (carry, r0) = split_u64(dest[idx0 + 0] as u64 + ayl * 2);
1047 dest[idx0 + 0] = r0 as u32;
1048
1049 let (carry, r1) = split_u64(dest[idx0 + 1] as u64 + carry + (ayh + azl + byl) * 2);
1050 dest[idx0 + 1] = r1 as u32;
1051
1052 let (carry, r2) = split_u64(dest[idx0 + 2] as u64 + carry + (azh + byh + bzl) * 2);
1053 dest[idx0 + 2] = r2 as u32;
1054
1055 let (mut carry, r3) = split_u64(dest[idx0 + 3] as u64 + carry + bzh * 2);
1056 dest[idx0 + 3] = r3 as u32;
1057
1058 let mut idx = idx0 + 4;
1059 while carry != 0 {
1060 let (c, overflow) = split_u64(dest[idx] as u64 + carry);
1061 dest[idx] = overflow as u32;
1062 carry = c;
1063 idx += 1;
1064 }
1065}
1066
1067pub(crate) fn multiply_quad_spread_into_wrapping(
1070 dest: &mut [u32],
1071 idx: usize,
1072 a: u32,
1073 b: u32,
1074 y: u32,
1075 z: u32,
1076) {
1077 let ay = a as u64 * y as u64;
1078 let az = a as u64 * z as u64;
1079
1080 let by = b as u64 * y as u64;
1081 let bz = b as u64 * z as u64;
1082
1083 let (ayh, ayl) = split_u64(ay);
1084 let (azh, azl) = split_u64(az);
1085 let (byh, byl) = split_u64(by);
1086 let (bzh, bzl) = split_u64(bz);
1087
1088 let wrap = dest.len();
1089 let mut idx = idx % wrap;
1090
1091 let (carry, r0) = split_u64(dest[idx] as u64 + ayl * 2);
1092 dest[idx] = r0 as u32;
1093
1094 idx = (idx + 1) % wrap;
1095 let (carry, r1) = split_u64(dest[idx] as u64 + carry + (ayh + azl + byl) * 2);
1096 dest[idx] = r1 as u32;
1097
1098 idx = (idx + 1) % wrap;
1099 let (carry, r2) = split_u64(dest[idx] as u64 + carry + (azh + byh + bzl) * 2);
1100 dest[idx] = r2 as u32;
1101
1102 idx = (idx + 1) % wrap;
1103 let (mut carry, r3) = split_u64(dest[idx] as u64 + carry + bzh * 2);
1104 dest[idx] = r3 as u32;
1105
1106 while carry != 0 {
1107 idx = (idx + 1) % wrap;
1108 let (c, overflow) = split_u64(dest[idx] as u64 + carry);
1109 dest[idx] = overflow as u32;
1110 carry = c;
1111 }
1112}
1113
1114#[cfg(test)]
1115mod test {
1116 use super::*;
1117 include!("multiplication.tests.rs");
1118}