bigdecimal 0.4.10

Arbitrary precision decimal numbers
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
use paste::paste;

mod multiply_scaled_u64_slices_with_prec_into {
    use super::*;

    macro_rules! impl_case {
        ($name:ident: $prec:literal => [$($le_d:literal),*] E $exp:literal) => {
            impl_case!($name: round=Up; $prec => [$($le_d),*] E $exp);
        };
        ($name:ident: round=$round:ident; $prec:literal => [$($le_d:literal),*] E $exp:literal) => {
            impl_case!($name: round=$round; $prec => Plus [$($le_d),*] E $exp);
        };
        ($name:ident: round=$round:ident; $prec:literal => $sign:ident [$($expected:literal),*] E $exp:literal) => {
            #[test]
            fn $name() {
                let a = input_a();
                let b = input_b();

                let prec = NonZeroU64::new($prec).unwrap();
                let expected: &[u64] = &[$($expected),*];
                let expected_scale = -$exp;

                let rounding = NonDigitRoundingData {
                    mode: RoundingMode::$round,
                    sign: Sign::$sign,
                };

                let mut product = WithScale::default();
                multiply_scaled_u64_slices_with_prec_into(
                    &mut product, a.as_digit_slice(), b.as_digit_slice(), prec, rounding
                );
                assert_eq!(&product.value.digits[..], &expected[..]);
                assert_eq!(product.scale, expected_scale);
            }
        };
    }

    mod case_1667660160137446952e158 {
        use super::*;

        fn input_a() -> WithScale<DigitVec<RADIX_u64, LittleEndian>> {
            WithScale {
                scale: 34,
                value: DigitVec::from_vec(vec![
                    16175263208544711346,
                    5279606946643537445,
                    15341572592040251541,
                    10541804148642044343,
                    7522665456306621740,
                    13427633752471237939,
                    16469249152156353442,
                    11787750781150891403,
                    3583949032441389106,
                    18383297448742447850,
                    365519312995810676,
                ]),
            }
        }

        mod times_2d998213en173 {
            use super::*;

            fn input_b() -> WithScale<DigitVec<RADIX_u64, LittleEndian>> {
                WithScale {
                    scale: 272,
                    value: DigitVec::from_vec(vec![
                        1344009339610453499,
                        6464650240578252661,
                        13739370975302393952,
                        1107949409989368443,
                        12288971738008765224,
                        1403
                    ]),
                }
            }

            impl_case!(prec19_roundup: round=Up;
                19 => [5000000000000000001] E -15);
            impl_case!(prec20_roundup: round=Up;
                20 => [13106511852580896769, 2] E -16);
            impl_case!(prec100_roundup: round=Up;
                100 => [1, 6059390473091416064, 5120748075179647364, 14006871066438625056, 15461642991872345491, 2340] E -96);
            impl_case!(neg_prec100_roundceiling: round=Ceiling;
                100 => Minus [0, 6059390473091416064, 5120748075179647364, 14006871066438625056, 15461642991872345491, 2340] E -96);
            impl_case!(neg_prec100_roundfloor: round=Floor;
                100 => Minus [1, 6059390473091416064, 5120748075179647364, 14006871066438625056, 15461642991872345491, 2340] E -96);
        }

        mod times_5996425554en186 {
            use super::*;

            fn input_b() -> WithScale<DigitVec<RADIX_u64, LittleEndian>> {
                WithScale {
                    scale: 204,
                    value: DigitVec::from_vec(
                        vec![12019064456476625820, 325066880]
                    ),
                }
            }

            impl_case!(prec1_roundup: round=Up; 1 => [1] E 0);
            impl_case!(prec1_rounddown: round=Down; 1 => [9] E -1);
            impl_case!(prec1_roundfloor: round=Floor; 1 => [9] E -1);

            impl_case!(neg_prec1_rounddown: round=Down; 1 => Minus [9] E -1);
            impl_case!(neg_prec1_roundfloor: round=Floor; 1 => Minus [1] E 0);

            impl_case!(prec10_roundup: round=Floor; 10 => Minus [1000000000] E -9);
            impl_case!(prec25_roundup: round=Floor; 25 => Minus [2003764205206896640, 54210] E -24);

            impl_case!(prec40_roundup: round=Up;
                40 => [13399721896776114178, 7145508105175220139, 29] E -40);
        }

        mod times_7303919561276644672e10 {
            use super::*;

            fn input_b() -> WithScale<DigitVec<RADIX_u64, LittleEndian>> {
                WithScale {
                    scale: 7,
                    value: DigitVec::from_vec(
                        vec![16568107915372457172, 39594627279977552]
                    ),
                }
            }

            impl_case!(prec1_up: round=Up; 1 => [2] E 205);
            impl_case!(prec1_down: round=Down; 1 => [1] E 205);
            impl_case!(prec11_up: round=Up; 11 => [12180455666] E 195);
            impl_case!(prec25: 25 => [7055331922361162211, 66030] E 181);

            impl_case!(prec_30_up: 30 => [571648947000381622, 6603038247] E 176);
            impl_case!(prec_31_up: 31 => [5716489470003816211, 66030382470] E 175);
            impl_case!(prec_57_up: 57 =>
                [3586467374344137641, 14971304827359975165, 357951420621793766] E 149);
            impl_case!(prec_75_up: 75 =>
                [16970166308972310451, 15246513073646694077, 13267213422529722744, 19404585394121069] E 131);
        }
    }

    mod random_values {
        use super::*;

        fn input_a() -> WithScale<BigDigitVec> {
            let a = vec![
                1745623865429447471,
                9152528756446785169,
                791242510259261833,
                8695454801466577396,
                8392994416015036890,
                2912771882945679798,
                8993891992610859856,
                8294679885144779824,
                8631634693823981953,
                366928013,
            ];

            WithScale {
                value: BigDigitVec::from_vec(a),
                scale: 100,
            }
        }

        fn input_b() -> WithScale<BigDigitVec> {
            let b = vec![
                518171251856216712,
                8211715648977239115,
                1585852536764360977,
                1552672896608399639,
                1044291249247,
            ];
            WithScale {
                value: BigDigitVec::from_vec(b),
                scale: -5,
            }
        }

        impl_case!(prec100: 100 => [
            7841754692876239913,
            2960052148898606502,
            16409584969160271562,
            16913806906493283056,
            14019529503395454758,
            513 ] E 77);

        impl_case!(prec10_rd: round=Down; 10 => [ 1097384700 ] E 167);
        impl_case!(prec20_rd: round=Down; 20 => [ 10973847000387492259 ] E 157);
        impl_case!(prec20_ru: round=Up;   20 => [ 10973847000387492260 ] E 157);

        impl_case!(prec45: 45 => [ 14618765252943857298, 6989353086943465649, 322492 ] E 132);
        impl_case!(prec46: 46 => [ 17060444013471711666, 14553298648306001649, 3224923 ] E 131);
    }
}

mod multiply_at_product_index {
    use super::*;

    macro_rules! impl_case {
        ($name:ident: $idx:literal => $expected:expr) => {
            #[test]
            fn $name() {
                let (a, b) = test_input();
                let a = BigDigitSliceP19::from_slice(&a);
                let b = BigDigitSliceP19::from_slice(&b);
                let mut product = DigitVec::<RADIX_10p19_u64, LittleEndian>::new();
                let expected: &[u64] = &$expected;
                multiply_at_product_index(&mut product, a, b, $idx);
                assert_eq!(product.digits, expected);
            }
        };
    }

    mod random_values {
        use super::*;

        fn test_input() -> (Vec<u64>, Vec<u64>) {
            let a = vec![
                1745623865429447471,
                9152528756446785169,
                791242510259261833,
                8695454801466577396,
                8392994416015036890,
                2912771882945679798,
                8993891992610859856,
                8294679885144779824,
                8631634693823981953,
                366928013,
            ];
            let b = vec![
                518171251856216712,
                8211715648977239115,
                1585852536764360977,
                1552672896608399639,
                1044291249247,
            ];
            (a, b)
        }

        impl_case!(case_1: 1 => [
            3259170168870572493,
            8530725771486096200,
            2353601569174537990,
            9915907985447408257,
            5505012768436728039,
            3337388859546710366,
            1787670230149175286,
            7565280555772427422,
            7309104897441821141,
            4201853743352582046,
            9605931707432557799,
            9324155135517901886,
            3179713980940485874,
            38
        ]);

        impl_case!(case_3: 3 => [
            4519975091742652829,
            9915907985447408256,
            5505012768436728039,
            3337388859546710366,
            1787670230149175286,
            7565280555772427422,
            7309104897441821141,
            4201853743352582046,
            9605931707432557799,
            9324155135517901886,
            3179713980940485874,
            38
        ]);

        impl_case!(case_9: 9 => [
            8171925425020376989,
            4201853743352582045,
            9605931707432557799,
            9324155135517901886,
            3179713980940485874,
            38
        ]);

        impl_case!(case_12: 12 => [
            7983943745001026698,
            3179713980940485874,
            38
        ]);

        impl_case!(case_20: 20 => []);
    }
}

mod multiply_big_int_with_ctx {
    use super::*;

    macro_rules! impl_case {
        (full => $expected:literal) => {
            #[test]
            fn case_full() {
                let (x, y) = test_input();
                let product = &x * &y;
                let expected: BigInt = $expected.parse().unwrap();

                assert_eq!(&expected, &product);
            }
        };
        ($prec:literal => $expected:literal E $exp:literal) => {
            paste! {
                #[test]
                fn [< case_prec $prec >] () {
                    impl_case!(
                        IMPL;
                        ctx=Context::default().with_prec($prec);
                        $expected;
                        $exp
                    );
                }
            }
        };
        ($prec:literal; $mode:ident => $expected:literal E $exp:literal) => {
            paste! {
                #[test]
                fn [< case_prec $prec _ $mode:lower >]() {
                    impl_case!(
                        IMPL;
                        ctx=Context::default().with_rounding_mode(RoundingMode::$mode).with_prec($prec);
                        $expected;
                        $exp
                    );
                }
            }
        };
        ($prec:literal; $($modes:ident),+ => $expected:literal E $exp:literal) => {
            $( impl_case!($prec; $modes => $expected E $exp); )*
        };
        (IMPL; ctx=$ctx:expr; $expected:literal; $exp:literal) => {
            let (x, y) = test_input();
            let ctx = $ctx.unwrap();
            let product = multiply_big_int_with_ctx(&x, &y, ctx);

            let expected: BigInt = $expected.parse().unwrap();
            let scale = -$exp;

            assert_eq!(&expected, &product.value);
            assert_eq!(&scale, &product.scale);
        };
    }

    mod mul_577874872717e492_696712038e285 {
        use super::*;

        fn test_input() -> (BigInt, BigInt) {
            let x: BigInt = "577874872717466911184559916156758198495131305219358809343652669536302387743158062880956367761473177845712351639985492473123959095758451817231985325403278703100241171849679780394380997111752306496891336078616237486336807931580623365870368160556723018500080769313066709500174011587939745841025646291922884710337974681230011250190261422246454991091897190225976651017177719025146752407491035501139104790891684620162820417602920652689929206945524922873810759445524737158705885775589194963686168193817138671875".parse().unwrap();
            let y: BigInt = "696712038660547059904752779034165119484624188403362872193018065005292090954487758438349971006124876297418423724096428714200094204277821355374358649621264188134962601815256767310343261823948242351360751280910536781247104655969073243119218479973070589731361603163735999605615737734639873901461504".parse().unwrap();
            (x, y)
        }
        impl_case!(100; Down => "4026123806616905180553157364566020245817156933504926464873554931196880658239704482799527614035787776" E 698);
        impl_case!(20; Down  => "40261238066169051805" E 778);
    }

    mod mul_1442862119e445_1049464e105 {
        use super::*;

        fn test_input() -> (BigInt, BigInt) {
            let x: BigInt = "14428621197889752189861398972981082461843826128512116303033203450866726426082853906596666646209600245865382634277766055876367040002473414960534339870779684891851540020597214991380071631960919603045037521801802725511393621544601218214902662462163496096667869677784522965589318809320143842055299565296240744974377213638202218555750884767181679713147685927591605307661717624963762005955819493848581352190387436454778284644628882915640133433043956756591796875".parse().unwrap();
            let y: BigInt = "1049464598544894921302784839734515848195965967618699631485860068380390543981052363225912818001120911046454804480".parse().unwrap();
            (x, y)
        }

        impl_case!(20; HalfEven  => "15142327152999729642" E 546);
        impl_case!(138; HalfDown => "151423271529997296423843423920943952557791563643246327643459830966880329966739641792530818647522102274133154353120322001711481566221946243" E 428);
        impl_case!(246; Up,
                        HalfUp   => "151423271529997296423843423920943952557791563643246327643459830966880329966739641792530818647522102274133154353120322001711481566221946242709348400715315872658516242116494741084148721184917688258189092970640993174313848612655419856309890747070313" E 320);
        impl_case!(246; Down,
                        HalfDown,
                        HalfEven => "151423271529997296423843423920943952557791563643246327643459830966880329966739641792530818647522102274133154353120322001711481566221946242709348400715315872658516242116494741084148721184917688258189092970640993174313848612655419856309890747070312" E 320);
        impl_case!(247; Up, Down => "1514232715299972964238434239209439525577915636432463276434598309668803299667396417925308186475221022741331543531203220017114815662219462427093484007153158726585162421164947410841487211849176882581890929706409931743138486126554198563098907470703125" E 319);
        impl_case!(248; Up, Down => "15142327152999729642384342392094395255779156364324632764345983096688032996673964179253081864752210227413315435312032200171148156622194624270934840071531587265851624211649474108414872118491768825818909297064099317431384861265541985630989074707031250" E 318);
        impl_case!(357; Down     => "151423271529997296423843423920943952557791563643246327643459830966880329966739641792530818647522102274133154353120322001711481566221946242709348400715315872658516242116494741084148721184917688258189092970640993174313848612655419856309890747070312500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" E 209);
    }

    mod mul_11552262607819902e131_75e161 {
        use super::*;

        fn test_input() -> (BigInt, BigInt) {
            let x: BigInt = "1155226260781990200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".parse().unwrap();
            let y: BigInt = "7500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".parse().unwrap();
            (x, y)
        }

        impl_case!(20                           => "86641969558649265000" E 290);
        impl_case!(18; HalfUp                   => "866419695586492650" E 292);
        impl_case!(17; HalfUp, HalfDown         => "86641969558649265" E 293);
        impl_case!(16; Up, HalfUp               => "8664196955864927" E 294);
        impl_case!(16; Down, HalfDown, HalfEven => "8664196955864926" E 294);
        impl_case!(15; Up, HalfDown             => "866419695586493" E 295);
        impl_case!(15; Down                     => "866419695586492" E 295);
        impl_case!( 3; HalfUp                   => "866" E 307);
    }

    mod mul_2301346222e107_14293213e315 {
        use super::*;

        fn test_input() -> (BigInt, BigInt) {
            let x: BigInt = "230134622236549555995211986626222699902919552403311068655782487235360869740373750138395520899795192776856789295000000".parse().unwrap();
            let y: BigInt = "14293213600958985303333846898378944669728091790434135672846064625014252175269303162751477769546102012233954333273726511104485055758813349716438744379331517132722718015116165694607959258435272025702738339275667597501313358033107443840555382841970678973851997248262639615206455939322314712306500000000000000000000000000000000".parse().unwrap();
            (x, y)
        }

        impl_case!(1 => "3" E 438);
        impl_case!(10 => "3289363313" E 429);
        impl_case!(20 => "32893633126030082513" E 419);
        impl_case!(401 => "32893633126030082513378632456028104243338158146601751534822570641115861940893690474203736021657204584394456560452273117013862292944834269220913901434456366640765512794407601501204644375698772310462659595240672712968083946415944676232524453019368460583076233422452053267394081654933088569072574309446551869537537085955808336137944176420693881753901339121561334586231165213326029020686758979692139589175" E 38);
        impl_case!(400; HalfUp   => "3289363312603008251337863245602810424333815814660175153482257064111586194089369047420373602165720458439445656045227311701386229294483426922091390143445636664076551279440760150120464437569877231046265959524067271296808394641594467623252445301936846058307623342245205326739408165493308856907257430944655186953753708595580833613794417642069388175390133912156133458623116521332602902068675897969213958918" E 39);
        impl_case!(400; HalfDown => "3289363312603008251337863245602810424333815814660175153482257064111586194089369047420373602165720458439445656045227311701386229294483426922091390143445636664076551279440760150120464437569877231046265959524067271296808394641594467623252445301936846058307623342245205326739408165493308856907257430944655186953753708595580833613794417642069388175390133912156133458623116521332602902068675897969213958917" E 39);
    }

    mod mul_166282988e757_855704757e288 {
        use super::*;

        fn test_input() -> (BigInt, BigInt) {
            let x: BigInt = "1662829881972302555130573804034884736045567192245210098539333943847359516964532887814910330238584574704591142597582120739098300776070255016531228502052315027932433758655554089934478913134076538917555237055311466963257200943418192284685329544412527781851150111516400149208425751400577475249704818681525213682644230996369594895101870162749874014287967075708189893449815333186508386746072349175785274400940465234953370696338639401851764570625527530834473094592285942335138352231629223479010378029739170207319201385183107178796700474330961290205720379495017762115091196226436689486111860406277126830834375106428374156802498831754786978409114271376697671477362897657305451012544150393117399631804227698370258868601667565428070820650330308154707381618209183216094970703125".parse().unwrap();
            let y: BigInt = "855704757901450759869356338513283551486583906378815084661323942969666040804246301726741288371813738860776552307977511102966634857016690379580472911872149121752146077285669707976656886280326152572122998172317660237359659093011810926589974967764428889136711853677544671180201059446857211098370670592".parse().unwrap();
            (x, y)
        }

        impl_case!(132 => "142289144158440709930589101331424815642676467582494920860869705909839132157013788030340030454912181312465691007673740386962890625000" E 931);
        impl_case!(63 => "142289144158440709930589101331424815642676467582494920860869706" E 1000);
        impl_case!(30 => "142289144158440709930589101331" E 1033);
        impl_case!(20 => "14228914415844070993" E 1043);
        impl_case!(19 => "1422891441584407099" E 1044);
    }

    // test (2^5000-1) * (2^1500-1)
    mod mul_2p5000m1_2p1501m1 {
        use super::*;

        fn test_input() -> (BigInt, BigInt) {
            let x: BigInt = "141246703213942603683520966701614733366889617518454111681368808585711816984270751255808912631671152637335603208431366082764203838069979338335971185726639923431051777851865399011877999645131707069373498212631323752553111215372844035950900535954860733418453405575566736801565587405464699640499050849699472357900905617571376618228216434213181520991556677126498651782204174061830939239176861341383294018240225838692725596147005144243281075275629495339093813198966735633606329691023842454125835888656873133981287240980008838073668221804264432910894030789020219440578198488267339768238872279902157420307247570510423845868872596735891805818727796435753018518086641356012851302546726823009250218328018251907340245449863183265637987862198511046362985461949587281119139907228004385942880953958816554567625296086916885774828934449941362416588675326940332561103664556982622206834474219811081872404929503481991376740379825998791411879802717583885498575115299471743469241117070230398103378615232793710290992656444842895511830355733152020804157920090041811951880456705515468349446182731742327685989277607620709525878318766488368348965015474997864119765441433356928012344111765735336393557879214937004347568208665958717764059293592887514292843557047089164876483116615691886203812997555690171892169733755224469032475078797830901321579940127337210694377283439922280274060798234786740434893458120198341101033812506720046609891160700284002100980452964039788704335302619337597862052192280371481132164147186514169090917191909375".parse().unwrap();
            let y: BigInt = "35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150406795437517399294548941469959754171038918004700847889956485329097264486802711583462946536682184340138629451355458264946342525383619389314960644665052551751442335509249173361130355796109709885580674313954210217657847432626760733004753275317192133674703563372783297041993227052663333668509952000175053355529058880434182538386715523683713208549375".parse().unwrap();
            (x, y)
        }

        impl_case!(100 => "4954180389441794407302644533158844937036173071799942385207702899881096950794929284226174201155309760" E 1857);
        impl_case!(70  => "4954180389441794407302644533158844937036173071799942385207702899881097" E 1887);
        impl_case!(20  => "49541803894417944073" E 1937);
    }

    mod multiply_313313e185_140912e85 {
        use super::*;

        fn test_input() -> (BigInt, BigInt) {
            let x: BigInt = "31331330514777647459696918012218766637269396231379435058341584170846149718531941093035596483272466942484919002494751588025494203950111183556196762802239021663296916615390846043521157975900649".parse().unwrap();
            let y: BigInt = "1409125393389843319552855599302577071349036214812589000980540875883362915766473073232671889".parse().unwrap();
            (x, y)
        }

        impl_case!(full => "44149773437063254678149469396251230458443452710019771114377331920312228495036605502543146558201981056772851870606187717471634519393139631393769297684773531284154562671396651882745113413784696354015721073630190690162770887707923095632780007819514677121000367593109419444597479155961");
        impl_case!(100  => "4414977343706325467814946939625123045844345271001977111437733192031222849503660550254314655820198106" E 181);
        impl_case!(50  => "44149773437063254678149469396251230458443452710020" E 231);
        impl_case!(21  => "441497734370632546781" E 260);
    }

    mod mul_354436071780069e151_282138326095801e70 {
        use super::*;

        fn test_input() -> (BigInt, BigInt) {
            let x: BigInt = "3544360717800690051921825754840028412915557760215486673759084471433756826848643934952495657908167389640789167410480517347773985344060322134315971203024120535921247142".parse().unwrap();
            let y: BigInt = "2821383260958014531084804730393168953719437088977599878666724657220634716408631037763".parse().unwrap();
            (x, y)
        }

        impl_case!(200; Up   => "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999979587838286624448431722853801267006" E 50);
        impl_case!(200; Down => "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999979587838286624448431722853801267005" E 50);
        impl_case!(166; Up   => "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998" E 84);
        impl_case!(166; Down => "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999997" E 84);
        impl_case!(165; Up   => "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" E 86);
        impl_case!(165; Down => "999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" E 85);
        impl_case!(42; Up => "100000000000000000000000000000000000000000" E 209);
        impl_case!(22; Up => "1000000000000000000000" E 229);
        impl_case!(21; Up => "100000000000000000000" E 230);
        impl_case!(20; Up => "10000000000000000000" E 231);
        impl_case!(19; Up => "1000000000000000000" E 232);
        impl_case!(12; Up => "100000000000" E 239);
        impl_case!(12; Down => "999999999999" E 238);
        impl_case!(2; Up => "10" E 249);
        impl_case!(2; Down => "99" E 248);
        impl_case!(1; Up, HalfUp => "1" E 250);
        impl_case!(1; Down => "9" E 249);
    }

    mod mul_3721418e448_3844674e161 {
        use super::*;

        fn test_input() -> (BigInt, BigInt) {
            let x: BigInt = "37214180020990129688144525415958680174157975522481928636541900907279612101437934903263895850798267657684166647521832553912867028735643169656904261854440137332351057065885513562123737325309196016024433700918100990040278606068777262035069231336055867161206731423272839919925319426271071135470308154818218588125994382305796706103307807638138902394400413759405500315832312273461261134673346351894542208780520017757692703697092184711436857469379901885986328125".parse().unwrap();
            let y: BigInt = "384467472657945478705050171808793258461219095507172038645145218810507057013081321321499154743364560076819504633305258370960191863566109907922325021911311899034388627258125176177530017308946900981633538093921103514946225947524282186623225866254314533377160053778776276453031176006567736506050524284200740234201681989688527171382167496044598504125969423204217194885709731987591265467004291805188733436497695584275662479958826872492302565650006868261814480548258209741016215533270514872064920715433587381471128142127411378792338183702243894864240468654283770230621234327560844588972472126092496338279872812038026604640358131717471991285825660709098949913655676881776223568791337070502357370402925535826378792284995488461006043177936586374698890722356736660003662109375".parse().unwrap();
            (x, y)
        }

        impl_case!(1220 => "14307641739707883586679338985784075376978599376076587159440407707473484422913380008679767889422355347578618773517358618682873816807001368824338399142290429730889921795132627329720311739245335457279882660403134178519487192193894827422017154794231967246548713182248254712192749435152248607256549045476459086684404679865181612177150422506682419296142751964295148026282623865246096746974909857474439409542650897431239188074724043848310873968922165900982577988822068956986831441597090874147542405989083220921853122209746471544669432201826149806457043393719329728030519620309220466905001009022724582301547918511296250822446396192324003728354373460047809727056243017571910340832631321081615757824717334420837535928747492488405758229871707378866111943107064677309884245984942614408304014573934636656429274910312463230088178109721849404398091245972145748205556337972593506762958354058055515482983023700007919157035627908661458407216568244912244912595573815702329952766665565695461070495291089051793343278543261429000685884437880347246913152237805580594025316169462092558252280687656044981784943452157349160827416439182889565322019088971898689733394885908687909675808992617947650750136428902947738350803774665109813213348388671875" E 0);
    }
}

mod test_multiply_quad_spread_into {
    use super::*;

    macro_rules! impl_case {
        ( wrapping: $($toks:tt)* ) => {
            impl_case!(multiply_quad_spread_into_wrapping; $($toks)*);
        };
        (
            $func:ident;
            $s:literal @ $n:literal,
            [ $a:literal, $b:literal, $y:literal, $z:literal] => $expected:expr
        ) => {
            paste!{
                #[test]
                fn [< case_ $n _ $a _ $b _ $y _ $z >]() {
                    let mut result = vec![0; $s];
                    $func(&mut result, $n, $a, $b, $y, $z);
                    let expected = &$expected;
                    assert_eq!(expected, result.as_slice());
                }
            }
        };
        ( $($toks:tt)* ) => {
            impl_case!(multiply_quad_spread_into; $($toks)*);
        };
    }

    impl_case!(
        8 @ 2,
        [2559712337, 684026673, 1163340730, 1823138616]
         => [0u32, 0, 3001179060, 4203670869, 1059648540, 580714756, 0, 0]);

    impl_case!(
        6 @ 1,
        [4294967295, 4294967295, 4294967295, 4294967295]
         => [0u32, 2, 0, 4294967292, 4294967295, 1]);

    impl_case!(
        wrapping: 8 @ 6,
        [2559712337, 684026673, 1163340730, 1823138616]
         => [1059648540u32, 580714756, 0, 0, 0, 0, 3001179060, 4203670869]);
}

#[cfg(all(test, property_tests))]
mod props {
    use super::*;
    use proptest::{self as pt};
    use proptest::prelude::*;
    use num_traits::FromPrimitive;

    fn random_f64() -> pt::num::f64::Any {
        use proptest::num::f64::*;
        NORMAL | SUBNORMAL | ZERO | NEGATIVE
    }

    fn rounding_modes() -> impl Strategy<Value = RoundingMode> {
        prop_oneof![
            Just(RoundingMode::Down),
            Just(RoundingMode::Up),
            Just(RoundingMode::HalfEven),
        ]
    }

    proptest! {
        #![proptest_config(ProptestConfig::with_cases(10_000))]

        #[test]
        fn test_multiply_f64_decimals_with_context(
            a in random_f64(), b in random_f64(), prec in 1..6000u64, mode in rounding_modes()
        ) {
            let prec = NonZeroU64::new(prec).unwrap();
            let a: BigDecimal = BigDecimal::from_f64(a).unwrap();
            let b: BigDecimal = BigDecimal::from_f64(b).unwrap();

            let a_times_b = &a * &b;
            let a_times_b_rounded = a_times_b.with_precision_round(prec, mode);

            let mut dest = BigDecimal::default();
            let ctx = Context::new(prec, mode);
            super::multiply_decimals_with_context(&mut dest, &a, &b, &ctx);

            prop_assert_eq!(a_times_b_rounded, dest)
        }
    }
}