Coverage Report

Created: 2025-07-01 06:50

/rust/registry/src/index.crates.io-6f17d22bba15001f/num-bigint-0.4.6/src/biguint/multiplication.rs
Line
Count
Source (jump to first uncovered line)
1
use super::addition::{__add2, add2};
2
use super::subtraction::sub2;
3
use super::{biguint_from_vec, cmp_slice, BigUint, IntDigits};
4
5
use crate::big_digit::{self, BigDigit, DoubleBigDigit};
6
use crate::Sign::{self, Minus, NoSign, Plus};
7
use crate::{BigInt, UsizePromotion};
8
9
use core::cmp::Ordering;
10
use core::iter::Product;
11
use core::ops::{Mul, MulAssign};
12
use num_traits::{CheckedMul, FromPrimitive, One, Zero};
13
14
#[inline]
15
0
pub(super) fn mac_with_carry(
16
0
    a: BigDigit,
17
0
    b: BigDigit,
18
0
    c: BigDigit,
19
0
    acc: &mut DoubleBigDigit,
20
0
) -> BigDigit {
21
0
    *acc += DoubleBigDigit::from(a);
22
0
    *acc += DoubleBigDigit::from(b) * DoubleBigDigit::from(c);
23
0
    let lo = *acc as BigDigit;
24
0
    *acc >>= big_digit::BITS;
25
0
    lo
26
0
}
27
28
#[inline]
29
0
fn mul_with_carry(a: BigDigit, b: BigDigit, acc: &mut DoubleBigDigit) -> BigDigit {
30
0
    *acc += DoubleBigDigit::from(a) * DoubleBigDigit::from(b);
31
0
    let lo = *acc as BigDigit;
32
0
    *acc >>= big_digit::BITS;
33
0
    lo
34
0
}
35
36
/// Three argument multiply accumulate:
37
/// acc += b * c
38
0
fn mac_digit(acc: &mut [BigDigit], b: &[BigDigit], c: BigDigit) {
39
0
    if c == 0 {
40
0
        return;
41
0
    }
42
0
43
0
    let mut carry = 0;
44
0
    let (a_lo, a_hi) = acc.split_at_mut(b.len());
45
46
0
    for (a, &b) in a_lo.iter_mut().zip(b) {
47
0
        *a = mac_with_carry(*a, b, c, &mut carry);
48
0
    }
49
50
0
    let (carry_hi, carry_lo) = big_digit::from_doublebigdigit(carry);
51
52
0
    let final_carry = if carry_hi == 0 {
53
0
        __add2(a_hi, &[carry_lo])
54
    } else {
55
0
        __add2(a_hi, &[carry_hi, carry_lo])
56
    };
57
0
    assert_eq!(final_carry, 0, "carry overflow during multiplication!");
58
0
}
59
60
0
fn bigint_from_slice(slice: &[BigDigit]) -> BigInt {
61
0
    BigInt::from(biguint_from_vec(slice.to_vec()))
62
0
}
63
64
/// Three argument multiply accumulate:
65
/// acc += b * c
66
#[allow(clippy::many_single_char_names)]
67
0
fn mac3(mut acc: &mut [BigDigit], mut b: &[BigDigit], mut c: &[BigDigit]) {
68
0
    // Least-significant zeros have no effect on the output.
69
0
    if let Some(&0) = b.first() {
70
0
        if let Some(nz) = b.iter().position(|&d| d != 0) {
71
0
            b = &b[nz..];
72
0
            acc = &mut acc[nz..];
73
0
        } else {
74
0
            return;
75
        }
76
0
    }
77
0
    if let Some(&0) = c.first() {
78
0
        if let Some(nz) = c.iter().position(|&d| d != 0) {
79
0
            c = &c[nz..];
80
0
            acc = &mut acc[nz..];
81
0
        } else {
82
0
            return;
83
        }
84
0
    }
85
86
0
    let acc = acc;
87
0
    let (x, y) = if b.len() < c.len() { (b, c) } else { (c, b) };
88
89
    // We use four algorithms for different input sizes.
90
    //
91
    // - For small inputs, long multiplication is fastest.
92
    // - If y is at least least twice as long as x, split using Half-Karatsuba.
93
    // - Next we use Karatsuba multiplication (Toom-2), which we have optimized
94
    //   to avoid unnecessary allocations for intermediate values.
95
    // - For the largest inputs we use Toom-3, which better optimizes the
96
    //   number of operations, but uses more temporary allocations.
97
    //
98
    // The thresholds are somewhat arbitrary, chosen by evaluating the results
99
    // of `cargo bench --bench bigint multiply`.
100
101
0
    if x.len() <= 32 {
102
        // Long multiplication:
103
0
        for (i, xi) in x.iter().enumerate() {
104
0
            mac_digit(&mut acc[i..], y, *xi);
105
0
        }
106
0
    } else if x.len() * 2 <= y.len() {
107
0
        // Karatsuba Multiplication for factors with significant length disparity.
108
0
        //
109
0
        // The Half-Karatsuba Multiplication Algorithm is a specialized case of
110
0
        // the normal Karatsuba multiplication algorithm, designed for the scenario
111
0
        // where y has at least twice as many base digits as x.
112
0
        //
113
0
        // In this case y (the longer input) is split into high2 and low2,
114
0
        // at m2 (half the length of y) and x (the shorter input),
115
0
        // is used directly without splitting.
116
0
        //
117
0
        // The algorithm then proceeds as follows:
118
0
        //
119
0
        // 1. Compute the product z0 = x * low2.
120
0
        // 2. Compute the product temp = x * high2.
121
0
        // 3. Adjust the weight of temp by adding m2 (* NBASE ^ m2)
122
0
        // 4. Add temp and z0 to obtain the final result.
123
0
        //
124
0
        // Proof:
125
0
        //
126
0
        // The algorithm can be derived from the original Karatsuba algorithm by
127
0
        // simplifying the formula when the shorter factor x is not split into
128
0
        // high and low parts, as shown below.
129
0
        //
130
0
        // Original Karatsuba formula:
131
0
        //
132
0
        //     result = (z2 * NBASE ^ (m2 × 2)) + ((z1 - z2 - z0) * NBASE ^ m2) + z0
133
0
        //
134
0
        // Substitutions:
135
0
        //
136
0
        //     low1 = x
137
0
        //     high1 = 0
138
0
        //
139
0
        // Applying substitutions:
140
0
        //
141
0
        //     z0 = (low1 * low2)
142
0
        //        = (x * low2)
143
0
        //
144
0
        //     z1 = ((low1 + high1) * (low2 + high2))
145
0
        //        = ((x + 0) * (low2 + high2))
146
0
        //        = (x * low2) + (x * high2)
147
0
        //
148
0
        //     z2 = (high1 * high2)
149
0
        //        = (0 * high2)
150
0
        //        = 0
151
0
        //
152
0
        // Simplified using the above substitutions:
153
0
        //
154
0
        //     result = (z2 * NBASE ^ (m2 × 2)) + ((z1 - z2 - z0) * NBASE ^ m2) + z0
155
0
        //            = (0 * NBASE ^ (m2 × 2)) + ((z1 - 0 - z0) * NBASE ^ m2) + z0
156
0
        //            = ((z1 - z0) * NBASE ^ m2) + z0
157
0
        //            = ((z1 - z0) * NBASE ^ m2) + z0
158
0
        //            = (x * high2) * NBASE ^ m2 + z0
159
0
        let m2 = y.len() / 2;
160
0
        let (low2, high2) = y.split_at(m2);
161
0
162
0
        // (x * high2) * NBASE ^ m2 + z0
163
0
        mac3(acc, x, low2);
164
0
        mac3(&mut acc[m2..], x, high2);
165
0
    } else if x.len() <= 256 {
166
        // Karatsuba multiplication:
167
        //
168
        // The idea is that we break x and y up into two smaller numbers that each have about half
169
        // as many digits, like so (note that multiplying by b is just a shift):
170
        //
171
        // x = x0 + x1 * b
172
        // y = y0 + y1 * b
173
        //
174
        // With some algebra, we can compute x * y with three smaller products, where the inputs to
175
        // each of the smaller products have only about half as many digits as x and y:
176
        //
177
        // x * y = (x0 + x1 * b) * (y0 + y1 * b)
178
        //
179
        // x * y = x0 * y0
180
        //       + x0 * y1 * b
181
        //       + x1 * y0 * b
182
        //       + x1 * y1 * b^2
183
        //
184
        // Let p0 = x0 * y0 and p2 = x1 * y1:
185
        //
186
        // x * y = p0
187
        //       + (x0 * y1 + x1 * y0) * b
188
        //       + p2 * b^2
189
        //
190
        // The real trick is that middle term:
191
        //
192
        //         x0 * y1 + x1 * y0
193
        //
194
        //       = x0 * y1 + x1 * y0 - p0 + p0 - p2 + p2
195
        //
196
        //       = x0 * y1 + x1 * y0 - x0 * y0 - x1 * y1 + p0 + p2
197
        //
198
        // Now we complete the square:
199
        //
200
        //       = -(x0 * y0 - x0 * y1 - x1 * y0 + x1 * y1) + p0 + p2
201
        //
202
        //       = -((x1 - x0) * (y1 - y0)) + p0 + p2
203
        //
204
        // Let p1 = (x1 - x0) * (y1 - y0), and substitute back into our original formula:
205
        //
206
        // x * y = p0
207
        //       + (p0 + p2 - p1) * b
208
        //       + p2 * b^2
209
        //
210
        // Where the three intermediate products are:
211
        //
212
        // p0 = x0 * y0
213
        // p1 = (x1 - x0) * (y1 - y0)
214
        // p2 = x1 * y1
215
        //
216
        // In doing the computation, we take great care to avoid unnecessary temporary variables
217
        // (since creating a BigUint requires a heap allocation): thus, we rearrange the formula a
218
        // bit so we can use the same temporary variable for all the intermediate products:
219
        //
220
        // x * y = p2 * b^2 + p2 * b
221
        //       + p0 * b + p0
222
        //       - p1 * b
223
        //
224
        // The other trick we use is instead of doing explicit shifts, we slice acc at the
225
        // appropriate offset when doing the add.
226
227
        // When x is smaller than y, it's significantly faster to pick b such that x is split in
228
        // half, not y:
229
0
        let b = x.len() / 2;
230
0
        let (x0, x1) = x.split_at(b);
231
0
        let (y0, y1) = y.split_at(b);
232
0
233
0
        // We reuse the same BigUint for all the intermediate multiplies and have to size p
234
0
        // appropriately here: x1.len() >= x0.len and y1.len() >= y0.len():
235
0
        let len = x1.len() + y1.len() + 1;
236
0
        let mut p = BigUint { data: vec![0; len] };
237
0
238
0
        // p2 = x1 * y1
239
0
        mac3(&mut p.data, x1, y1);
240
0
241
0
        // Not required, but the adds go faster if we drop any unneeded 0s from the end:
242
0
        p.normalize();
243
0
244
0
        add2(&mut acc[b..], &p.data);
245
0
        add2(&mut acc[b * 2..], &p.data);
246
0
247
0
        // Zero out p before the next multiply:
248
0
        p.data.truncate(0);
249
0
        p.data.resize(len, 0);
250
0
251
0
        // p0 = x0 * y0
252
0
        mac3(&mut p.data, x0, y0);
253
0
        p.normalize();
254
0
255
0
        add2(acc, &p.data);
256
0
        add2(&mut acc[b..], &p.data);
257
0
258
0
        // p1 = (x1 - x0) * (y1 - y0)
259
0
        // We do this one last, since it may be negative and acc can't ever be negative:
260
0
        let (j0_sign, j0) = sub_sign(x1, x0);
261
0
        let (j1_sign, j1) = sub_sign(y1, y0);
262
0
263
0
        match j0_sign * j1_sign {
264
0
            Plus => {
265
0
                p.data.truncate(0);
266
0
                p.data.resize(len, 0);
267
0
268
0
                mac3(&mut p.data, &j0.data, &j1.data);
269
0
                p.normalize();
270
0
271
0
                sub2(&mut acc[b..], &p.data);
272
0
            }
273
0
            Minus => {
274
0
                mac3(&mut acc[b..], &j0.data, &j1.data);
275
0
            }
276
0
            NoSign => (),
277
        }
278
    } else {
279
        // Toom-3 multiplication:
280
        //
281
        // Toom-3 is like Karatsuba above, but dividing the inputs into three parts.
282
        // Both are instances of Toom-Cook, using `k=3` and `k=2` respectively.
283
        //
284
        // The general idea is to treat the large integers digits as
285
        // polynomials of a certain degree and determine the coefficients/digits
286
        // of the product of the two via interpolation of the polynomial product.
287
0
        let i = y.len() / 3 + 1;
288
0
289
0
        let x0_len = Ord::min(x.len(), i);
290
0
        let x1_len = Ord::min(x.len() - x0_len, i);
291
0
292
0
        let y0_len = i;
293
0
        let y1_len = Ord::min(y.len() - y0_len, i);
294
0
295
0
        // Break x and y into three parts, representating an order two polynomial.
296
0
        // t is chosen to be the size of a digit so we can use faster shifts
297
0
        // in place of multiplications.
298
0
        //
299
0
        // x(t) = x2*t^2 + x1*t + x0
300
0
        let x0 = bigint_from_slice(&x[..x0_len]);
301
0
        let x1 = bigint_from_slice(&x[x0_len..x0_len + x1_len]);
302
0
        let x2 = bigint_from_slice(&x[x0_len + x1_len..]);
303
0
304
0
        // y(t) = y2*t^2 + y1*t + y0
305
0
        let y0 = bigint_from_slice(&y[..y0_len]);
306
0
        let y1 = bigint_from_slice(&y[y0_len..y0_len + y1_len]);
307
0
        let y2 = bigint_from_slice(&y[y0_len + y1_len..]);
308
0
309
0
        // Let w(t) = x(t) * y(t)
310
0
        //
311
0
        // This gives us the following order-4 polynomial.
312
0
        //
313
0
        // w(t) = w4*t^4 + w3*t^3 + w2*t^2 + w1*t + w0
314
0
        //
315
0
        // We need to find the coefficients w4, w3, w2, w1 and w0. Instead
316
0
        // of simply multiplying the x and y in total, we can evaluate w
317
0
        // at 5 points. An n-degree polynomial is uniquely identified by (n + 1)
318
0
        // points.
319
0
        //
320
0
        // It is arbitrary as to what points we evaluate w at but we use the
321
0
        // following.
322
0
        //
323
0
        // w(t) at t = 0, 1, -1, -2 and inf
324
0
        //
325
0
        // The values for w(t) in terms of x(t)*y(t) at these points are:
326
0
        //
327
0
        // let a = w(0)   = x0 * y0
328
0
        // let b = w(1)   = (x2 + x1 + x0) * (y2 + y1 + y0)
329
0
        // let c = w(-1)  = (x2 - x1 + x0) * (y2 - y1 + y0)
330
0
        // let d = w(-2)  = (4*x2 - 2*x1 + x0) * (4*y2 - 2*y1 + y0)
331
0
        // let e = w(inf) = x2 * y2 as t -> inf
332
0
333
0
        // x0 + x2, avoiding temporaries
334
0
        let p = &x0 + &x2;
335
0
336
0
        // y0 + y2, avoiding temporaries
337
0
        let q = &y0 + &y2;
338
0
339
0
        // x2 - x1 + x0, avoiding temporaries
340
0
        let p2 = &p - &x1;
341
0
342
0
        // y2 - y1 + y0, avoiding temporaries
343
0
        let q2 = &q - &y1;
344
0
345
0
        // w(0)
346
0
        let r0 = &x0 * &y0;
347
0
348
0
        // w(inf)
349
0
        let r4 = &x2 * &y2;
350
0
351
0
        // w(1)
352
0
        let r1 = (p + x1) * (q + y1);
353
0
354
0
        // w(-1)
355
0
        let r2 = &p2 * &q2;
356
0
357
0
        // w(-2)
358
0
        let r3 = ((p2 + x2) * 2 - x0) * ((q2 + y2) * 2 - y0);
359
0
360
0
        // Evaluating these points gives us the following system of linear equations.
361
0
        //
362
0
        //  0  0  0  0  1 | a
363
0
        //  1  1  1  1  1 | b
364
0
        //  1 -1  1 -1  1 | c
365
0
        // 16 -8  4 -2  1 | d
366
0
        //  1  0  0  0  0 | e
367
0
        //
368
0
        // The solved equation (after gaussian elimination or similar)
369
0
        // in terms of its coefficients:
370
0
        //
371
0
        // w0 = w(0)
372
0
        // w1 = w(0)/2 + w(1)/3 - w(-1) + w(-2)/6 - 2*w(inf)
373
0
        // w2 = -w(0) + w(1)/2 + w(-1)/2 - w(inf)
374
0
        // w3 = -w(0)/2 + w(1)/6 + w(-1)/2 - w(-2)/6 + 2*w(inf)
375
0
        // w4 = w(inf)
376
0
        //
377
0
        // This particular sequence is given by Bodrato and is an interpolation
378
0
        // of the above equations.
379
0
        let mut comp3: BigInt = (r3 - &r1) / 3u32;
380
0
        let mut comp1: BigInt = (r1 - &r2) >> 1;
381
0
        let mut comp2: BigInt = r2 - &r0;
382
0
        comp3 = ((&comp2 - comp3) >> 1) + (&r4 << 1);
383
0
        comp2 += &comp1 - &r4;
384
0
        comp1 -= &comp3;
385
386
        // Recomposition. The coefficients of the polynomial are now known.
387
        //
388
        // Evaluate at w(t) where t is our given base to get the result.
389
        //
390
        //     let bits = u64::from(big_digit::BITS) * i as u64;
391
        //     let result = r0
392
        //         + (comp1 << bits)
393
        //         + (comp2 << (2 * bits))
394
        //         + (comp3 << (3 * bits))
395
        //         + (r4 << (4 * bits));
396
        //     let result_pos = result.to_biguint().unwrap();
397
        //     add2(&mut acc[..], &result_pos.data);
398
        //
399
        // But with less intermediate copying:
400
0
        for (j, result) in [&r0, &comp1, &comp2, &comp3, &r4].iter().enumerate().rev() {
401
0
            match result.sign() {
402
0
                Plus => add2(&mut acc[i * j..], result.digits()),
403
0
                Minus => sub2(&mut acc[i * j..], result.digits()),
404
0
                NoSign => {}
405
            }
406
        }
407
    }
408
0
}
409
410
0
fn mul3(x: &[BigDigit], y: &[BigDigit]) -> BigUint {
411
0
    let len = x.len() + y.len() + 1;
412
0
    let mut prod = BigUint { data: vec![0; len] };
413
0
414
0
    mac3(&mut prod.data, x, y);
415
0
    prod.normalized()
416
0
}
417
418
0
fn scalar_mul(a: &mut BigUint, b: BigDigit) {
419
0
    match b {
420
0
        0 => a.set_zero(),
421
0
        1 => {}
422
        _ => {
423
0
            if b.is_power_of_two() {
424
0
                *a <<= b.trailing_zeros();
425
0
            } else {
426
0
                let mut carry = 0;
427
0
                for a in a.data.iter_mut() {
428
0
                    *a = mul_with_carry(*a, b, &mut carry);
429
0
                }
430
0
                if carry != 0 {
431
0
                    a.data.push(carry as BigDigit);
432
0
                }
433
            }
434
        }
435
    }
436
0
}
437
438
0
fn sub_sign(mut a: &[BigDigit], mut b: &[BigDigit]) -> (Sign, BigUint) {
439
0
    // Normalize:
440
0
    if let Some(&0) = a.last() {
441
0
        a = &a[..a.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)];
442
0
    }
443
0
    if let Some(&0) = b.last() {
444
0
        b = &b[..b.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)];
445
0
    }
446
447
0
    match cmp_slice(a, b) {
448
        Ordering::Greater => {
449
0
            let mut a = a.to_vec();
450
0
            sub2(&mut a, b);
451
0
            (Plus, biguint_from_vec(a))
452
        }
453
        Ordering::Less => {
454
0
            let mut b = b.to_vec();
455
0
            sub2(&mut b, a);
456
0
            (Minus, biguint_from_vec(b))
457
        }
458
0
        Ordering::Equal => (NoSign, BigUint::ZERO),
459
    }
460
0
}
461
462
macro_rules! impl_mul {
463
    ($(impl Mul<$Other:ty> for $Self:ty;)*) => {$(
464
        impl Mul<$Other> for $Self {
465
            type Output = BigUint;
466
467
            #[inline]
468
0
            fn mul(self, other: $Other) -> BigUint {
469
0
                match (&*self.data, &*other.data) {
470
0
                    // multiply by zero
471
0
                    (&[], _) | (_, &[]) => BigUint::ZERO,
472
                    // multiply by a scalar
473
0
                    (_, &[digit]) => self * digit,
474
0
                    (&[digit], _) => other * digit,
475
                    // full multiplication
476
0
                    (x, y) => mul3(x, y),
477
                }
478
0
            }
Unexecuted instantiation: <num_bigint::biguint::BigUint as core::ops::arith::Mul>::mul
Unexecuted instantiation: <num_bigint::biguint::BigUint as core::ops::arith::Mul<&num_bigint::biguint::BigUint>>::mul
Unexecuted instantiation: <&num_bigint::biguint::BigUint as core::ops::arith::Mul>::mul
Unexecuted instantiation: <&num_bigint::biguint::BigUint as core::ops::arith::Mul<num_bigint::biguint::BigUint>>::mul
479
        }
480
    )*}
481
}
482
impl_mul! {
483
    impl Mul<BigUint> for BigUint;
484
    impl Mul<BigUint> for &BigUint;
485
    impl Mul<&BigUint> for BigUint;
486
    impl Mul<&BigUint> for &BigUint;
487
}
488
489
macro_rules! impl_mul_assign {
490
    ($(impl MulAssign<$Other:ty> for BigUint;)*) => {$(
491
        impl MulAssign<$Other> for BigUint {
492
            #[inline]
493
0
            fn mul_assign(&mut self, other: $Other) {
494
0
                match (&*self.data, &*other.data) {
495
0
                    // multiply by zero
496
0
                    (&[], _) => {},
497
0
                    (_, &[]) => self.set_zero(),
498
                    // multiply by a scalar
499
0
                    (_, &[digit]) => *self *= digit,
500
0
                    (&[digit], _) => *self = other * digit,
501
                    // full multiplication
502
0
                    (x, y) => *self = mul3(x, y),
503
                }
504
0
            }
Unexecuted instantiation: <num_bigint::biguint::BigUint as core::ops::arith::MulAssign<&num_bigint::biguint::BigUint>>::mul_assign
Unexecuted instantiation: <num_bigint::biguint::BigUint as core::ops::arith::MulAssign>::mul_assign
505
        }
506
    )*}
507
}
508
impl_mul_assign! {
509
    impl MulAssign<BigUint> for BigUint;
510
    impl MulAssign<&BigUint> for BigUint;
511
}
512
513
promote_unsigned_scalars!(impl Mul for BigUint, mul);
514
promote_unsigned_scalars_assign!(impl MulAssign for BigUint, mul_assign);
515
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<u32> for BigUint, mul);
516
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<u64> for BigUint, mul);
517
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<u128> for BigUint, mul);
518
519
impl Mul<u32> for BigUint {
520
    type Output = BigUint;
521
522
    #[inline]
523
0
    fn mul(mut self, other: u32) -> BigUint {
524
0
        self *= other;
525
0
        self
526
0
    }
527
}
528
impl MulAssign<u32> for BigUint {
529
    #[inline]
530
0
    fn mul_assign(&mut self, other: u32) {
531
0
        scalar_mul(self, other as BigDigit);
532
0
    }
533
}
534
535
impl Mul<u64> for BigUint {
536
    type Output = BigUint;
537
538
    #[inline]
539
0
    fn mul(mut self, other: u64) -> BigUint {
540
0
        self *= other;
541
0
        self
542
0
    }
543
}
544
impl MulAssign<u64> for BigUint {
545
    cfg_digit!(
546
        #[inline]
547
        fn mul_assign(&mut self, other: u64) {
548
            if let Some(other) = BigDigit::from_u64(other) {
549
                scalar_mul(self, other);
550
            } else {
551
                let (hi, lo) = big_digit::from_doublebigdigit(other);
552
                *self = mul3(&self.data, &[lo, hi]);
553
            }
554
        }
555
556
        #[inline]
557
0
        fn mul_assign(&mut self, other: u64) {
558
0
            scalar_mul(self, other);
559
0
        }
560
    );
561
}
562
563
impl Mul<u128> for BigUint {
564
    type Output = BigUint;
565
566
    #[inline]
567
0
    fn mul(mut self, other: u128) -> BigUint {
568
0
        self *= other;
569
0
        self
570
0
    }
571
}
572
573
impl MulAssign<u128> for BigUint {
574
    cfg_digit!(
575
        #[inline]
576
        fn mul_assign(&mut self, other: u128) {
577
            if let Some(other) = BigDigit::from_u128(other) {
578
                scalar_mul(self, other);
579
            } else {
580
                *self = match super::u32_from_u128(other) {
581
                    (0, 0, c, d) => mul3(&self.data, &[d, c]),
582
                    (0, b, c, d) => mul3(&self.data, &[d, c, b]),
583
                    (a, b, c, d) => mul3(&self.data, &[d, c, b, a]),
584
                };
585
            }
586
        }
587
588
        #[inline]
589
0
        fn mul_assign(&mut self, other: u128) {
590
0
            if let Some(other) = BigDigit::from_u128(other) {
591
0
                scalar_mul(self, other);
592
0
            } else {
593
0
                let (hi, lo) = big_digit::from_doublebigdigit(other);
594
0
                *self = mul3(&self.data, &[lo, hi]);
595
0
            }
596
0
        }
597
    );
598
}
599
600
impl CheckedMul for BigUint {
601
    #[inline]
602
0
    fn checked_mul(&self, v: &BigUint) -> Option<BigUint> {
603
0
        Some(self.mul(v))
604
0
    }
605
}
606
607
impl_product_iter_type!(BigUint);
608
609
#[test]
610
fn test_sub_sign() {
611
    use crate::BigInt;
612
    use num_traits::Num;
613
614
    fn sub_sign_i(a: &[BigDigit], b: &[BigDigit]) -> BigInt {
615
        let (sign, val) = sub_sign(a, b);
616
        BigInt::from_biguint(sign, val)
617
    }
618
619
    let a = BigUint::from_str_radix("265252859812191058636308480000000", 10).unwrap();
620
    let b = BigUint::from_str_radix("26525285981219105863630848000000", 10).unwrap();
621
    let a_i = BigInt::from(a.clone());
622
    let b_i = BigInt::from(b.clone());
623
624
    assert_eq!(sub_sign_i(&a.data, &b.data), &a_i - &b_i);
625
    assert_eq!(sub_sign_i(&b.data, &a.data), &b_i - &a_i);
626
}