dashu-float 0.4.3

A big float library supporting arbitrary precision, arbitrary base and arbitrary rounding mode
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
use core::str::FromStr;
use dashu_base::{ParseError, Sign};
use dashu_float::{round::mode, DBig, FBig};
use dashu_int::{DoubleWord, IBig, Word};

mod helper_macros;
type FBin = FBig;
type FOct = FBig<mode::Zero, 8>;
type FHex = FBig<mode::Zero, 16>;

#[test]
fn test_default() {
    assert_eq!(FBin::default(), fbig!(0));
    assert_eq!(DBig::default(), dbig!(0));
}

// radix independent cases: (text, mantissa, exponent, precision)
const FROM_STR_COMMON_CASES: [(&str, i64, isize, usize); 28] = [
    //
    // unsigned
    //
    ("0.0", 0, 0, 2),
    (".0", 0, 0, 1),
    ("1", 1, 0, 1),
    ("1.", 1, 0, 1),
    ("010", 1, 1, 3),
    ("010.", 1, 1, 3),
    (".1", 1, -1, 1),
    (".010", 1, -2, 3),
    ("1.0000", 1, 0, 5),
    ("1000.0000", 1, 3, 8),
    ("0000.0001", 1, -4, 8),
    ("10_00_.00_00", 1, 3, 8),
    ("00_00._00_01", 1, -4, 8),
    //
    // signed
    //
    ("-0.0", 0, 0, 2),
    ("-.0", 0, 0, 1),
    ("-1", -1, 0, 1),
    ("-1.", -1, 0, 1),
    ("-010", -1, 1, 3),
    ("-010.", -1, 1, 3),
    ("-.1", -1, -1, 1),
    ("-.010", -1, -2, 3),
    ("-1.0000", -1, 0, 5),
    ("+1000.0000", 1, 3, 8),
    ("-1000.0000", -1, 3, 8),
    ("0000.0001", 1, -4, 8),
    ("-0000.0001", -1, -4, 8),
    ("-10_00_.00_00", -1, 3, 8),
    ("-_00_00_._00_01", -1, -4, 8),
];

#[test]
fn test_from_str_decimal() {
    let test_cases = [
        // scientific
        ("2e0", 2, 0, 1),
        ("10e5", 1, 6, 2),
        ("-2E-7", -2, -7, 1),
        ("3.e4", 3, 4, 1),
        ("-.6e-1", -6, -2, 1),
        ("-12_34_.56_78e9", -12345678, 5, 8),
    ];
    for (text, man, exp, prec) in FROM_STR_COMMON_CASES.iter().copied().chain(test_cases) {
        let val = DBig::from_str(text).unwrap();
        assert_eq!(val, DBig::from_parts(IBig::from(man), exp));
        assert_eq!(val.precision(), prec);
    }

    // error cases
    assert_eq!(DBig::from_str("f"), Err(ParseError::InvalidDigit));
    assert_eq!(DBig::from_str("e"), Err(ParseError::NoDigits));
    assert_eq!(DBig::from_str("."), Err(ParseError::NoDigits));
    assert_eq!(DBig::from_str(".e"), Err(ParseError::NoDigits));
    assert_eq!(DBig::from_str("-."), Err(ParseError::NoDigits));
    assert_eq!(DBig::from_str("-.e"), Err(ParseError::NoDigits));
    assert_eq!(DBig::from_str("-abc.def"), Err(ParseError::InvalidDigit));
    assert_eq!(DBig::from_str("0b1.1"), Err(ParseError::InvalidDigit));
    assert_eq!(DBig::from_str("0o2.2"), Err(ParseError::InvalidDigit));
    assert_eq!(DBig::from_str("0x2.2"), Err(ParseError::InvalidDigit));
    assert_eq!(DBig::from_str("一.二"), Err(ParseError::InvalidDigit));
    assert_eq!(DBig::from_str("一.二E三"), Err(ParseError::InvalidDigit));
}

#[test]
fn test_from_str_binary() {
    let test_cases = [
        //
        // scientific with 'b' notation
        //
        ("10b0", 1, 1, 2),
        ("0110b5", 3, 6, 4),
        ("-10B-7", -1, -6, 2),
        ("11.b4", 3, 4, 2),
        ("-.11b4", -3, 2, 2),
        ("-.0110B-1", -3, -4, 4),
        ("-1100_0100_.0101_1010b3", -25133, -4, 16),
        //
        // with hexadecimal prefix
        //
        ("0x2", 2, 0, 4),
        ("-0x02", -2, 0, 8),
        ("0x.2", 1, -3, 4),
        ("0x2.2", 17, -3, 8),
        ("0xa", 5, 1, 4),
        ("0xb", 11, 0, 4),
        ("-0x0_f.2_0", -121, -3, 16),
        ("0x00100", 1, 8, 20),
        ("-0x010.00", -1, 4, 20),
        //
        // scientific with 'p' notation
        //
        ("0x2p0", 1, 1, 4),
        ("0x6p5", 3, 6, 4),
        ("-0x2P-7", -1, -6, 4),
        ("0x3.p4", 3, 4, 4),
        ("-0x0.6p-1", -3, -4, 8),
        ("-0x.1p0", -1, -4, 4),
        ("-0xc4.5ap3", -25133, -4, 16),
        ("0x00001p2", 1, 2, 20),
        ("-0x001.00p2", -1, 2, 20),
    ];
    for (text, man, exp, prec) in FROM_STR_COMMON_CASES.iter().copied().chain(test_cases) {
        let val = FBin::from_str(text).unwrap();
        assert_eq!(val, FBin::from_parts(IBig::from(man), exp));
        assert_eq!(val.precision(), prec);
    }

    assert_eq!(FBin::from_str("p"), Err(ParseError::InvalidDigit));
    assert_eq!(FBin::from_str("."), Err(ParseError::NoDigits));
    assert_eq!(FBin::from_str("1.0e8"), Err(ParseError::InvalidDigit));
    assert_eq!(FBin::from_str("0o2.2"), Err(ParseError::InvalidDigit));
    assert_eq!(FBin::from_str("一.二"), Err(ParseError::InvalidDigit));
    assert_eq!(FBin::from_str("一.二p三"), Err(ParseError::InvalidDigit));

    // prefix `0x` is required in following cases
    assert_eq!(FBin::from_str("1p8"), Err(ParseError::InvalidDigit));
    assert_eq!(FBin::from_str(".1p8"), Err(ParseError::InvalidDigit));
    assert_eq!(FBin::from_str("1.0p8"), Err(ParseError::InvalidDigit));
}

#[test]
fn test_from_str_oct_hex() {
    let oct_cases = [
        //
        // scientific with 'o' notation
        //
        ("10o0", 1, 1, 2),
        ("0770o5", 63, 6, 4),
        ("-30O-7", -3, -6, 2),
        ("11.o4", 9, 4, 2),
        ("-.11o4", -9, 2, 2),
        ("-.0700O-1", -7, -3, 4),
        ("-06_25_.13_30o3", -207451, 0, 8),
    ];
    for (text, man, exp, prec) in FROM_STR_COMMON_CASES.iter().copied().chain(oct_cases) {
        let val = FOct::from_str(text).unwrap();
        assert_eq!(val, FOct::from_parts(IBig::from(man), exp));
        assert_eq!(val.precision(), prec);
    }
    assert_eq!(FOct::from_str("f"), Err(ParseError::InvalidDigit));
    assert_eq!(FOct::from_str("O"), Err(ParseError::NoDigits));
    assert_eq!(FOct::from_str("."), Err(ParseError::NoDigits));
    assert_eq!(FOct::from_str("1.0e8"), Err(ParseError::InvalidDigit));
    assert_eq!(FOct::from_str("0b1.1"), Err(ParseError::InvalidDigit));
    assert_eq!(FOct::from_str("0o2.2"), Err(ParseError::InvalidDigit));
    assert_eq!(FOct::from_str("0x3O0"), Err(ParseError::InvalidDigit));
    assert_eq!(FOct::from_str("-0x.1o0"), Err(ParseError::InvalidDigit));
    assert_eq!(FOct::from_str("一.二"), Err(ParseError::InvalidDigit));
    assert_eq!(FOct::from_str("一.二o三"), Err(ParseError::InvalidDigit));

    let hex_cases = [
        //
        // scientific with 'h' notation
        //
        ("10h0", 1, 1, 2),
        ("0bb0h5", 187, 6, 4),
        ("-d0H-7", -13, -6, 2),
        ("11.h4", 17, 4, 2),
        ("-.11h4", -17, 2, 2),
        ("-.0f00H-1", -15, -3, 4),
        ("-0a_db_.74h-3", -711540, -5, 6),
    ];
    for (text, man, exp, prec) in FROM_STR_COMMON_CASES.iter().copied().chain(hex_cases) {
        let val = FHex::from_str(text).unwrap();
        assert_eq!(val, FHex::from_parts(IBig::from(man), exp));
        assert_eq!(val.precision(), prec);
    }
    assert_eq!(FHex::from_str("H"), Err(ParseError::NoDigits));
    assert_eq!(FHex::from_str("."), Err(ParseError::NoDigits));
    assert_eq!(FHex::from_str("0o2.2"), Err(ParseError::InvalidDigit));
    assert_eq!(FHex::from_str("0x3H0"), Err(ParseError::InvalidDigit));
    assert_eq!(FHex::from_str("-0x.1h0"), Err(ParseError::InvalidDigit));
    assert_eq!(FHex::from_str("一.二"), Err(ParseError::InvalidDigit));
    assert_eq!(FHex::from_str("一.二h三"), Err(ParseError::InvalidDigit));
}

#[test]
fn test_from_str_other_bases() {
    assert_eq!(
        FBig::<mode::Zero, 3>::from_str("12.21").unwrap(),
        FBig::<mode::Zero, 3>::from_parts(ibig!(52), -2)
    );
    assert_eq!(
        FBig::<mode::Zero, 20>::from_str("gg.hh@12").unwrap(),
        FBig::<mode::Zero, 20>::from_parts(ibig!(134757), 10)
    );
    assert_eq!(
        FBig::<mode::Zero, 30>::from_str("gg.hh@-12").unwrap(),
        FBig::<mode::Zero, 30>::from_parts(ibig!(446927), -14)
    );
}

#[test]
fn test_from_parts() {
    assert_eq!(FBin::from_parts(ibig!(0), 2), FBin::ZERO);
    assert_eq!(FBin::from_parts(ibig!(-4), -2), FBin::NEG_ONE);
    assert_eq!(FBin::from_parts(ibig!(4), 0), FBin::from_parts(ibig!(1), 2));
    assert_eq!(FBin::from_parts(ibig!(-4), 0), FBin::from_parts(ibig!(-1), 2));
    assert_eq!(FBin::from_parts(ibig!(1) << 200, 0), FBin::from_parts(ibig!(1), 200));

    assert_eq!(FBin::from_parts_const(Sign::Negative, 0, 2, None), FBin::ZERO);
    assert_eq!(FBin::from_parts_const(Sign::Negative, 1, 0, None), FBin::NEG_ONE);
    assert_eq!(
        FBin::from_parts_const(Sign::Positive, 4, 0, None),
        FBin::from_parts(ibig!(1), 2)
    );
    assert_eq!(
        FBin::from_parts_const(Sign::Positive, 1 << (Word::BITS - 1), 0, None),
        FBin::from_parts(ibig!(1), (Word::BITS - 1) as isize)
    );
    assert_eq!(
        FBin::from_parts_const(Sign::Positive, 1 << (DoubleWord::BITS - 1), 0, None),
        FBin::from_parts(ibig!(1), (DoubleWord::BITS - 1) as isize)
    );

    assert_eq!(DBig::from_parts(ibig!(0), 2), DBig::ZERO);
    assert_eq!(DBig::from_parts(ibig!(-100), -2), DBig::NEG_ONE);
    assert_eq!(DBig::from_parts(ibig!(200), 0), DBig::from_parts(ibig!(2), 2));
    assert_eq!(DBig::from_parts(ibig!(-400), 0), DBig::from_parts(ibig!(-4), 2));
    assert_eq!(DBig::from_parts(ibig!(10).pow(200), 0), DBig::from_parts(ibig!(1), 200));

    assert_eq!(DBig::from_parts_const(Sign::Negative, 0, 2, None), DBig::ZERO);
    assert_eq!(DBig::from_parts_const(Sign::Negative, 100, -2, None), DBig::NEG_ONE);
    assert_eq!(
        DBig::from_parts_const(Sign::Positive, 200, 0, None),
        DBig::from_parts(ibig!(2), 2)
    );
    assert_eq!(
        DBig::from_parts_const(Sign::Negative, 100200, 0, None),
        DBig::from_parts_const(Sign::Negative, 1002, 2, None)
    );
}

#[test]
#[rustfmt::skip::macros(fbig)]
fn test_format_binary() {
    assert_eq!(format!("{}", fbig!(0x0)), "0");
    assert_eq!(format!("{}", fbig!(0x1)), "1");
    assert_eq!(format!("{}", fbig!(-0x1)), "-1");
    assert_eq!(format!("{}", fbig!(0x1p4)), "10000");
    assert_eq!(format!("{}", fbig!(-0x1p4)), "-10000");
    assert_eq!(format!("{}", fbig!(0x1p-1)), "0.1");
    assert_eq!(format!("{}", fbig!(-0x1p-1)), "-0.1");
    assert_eq!(format!("{}", fbig!(0x1p-4)), "0.0001");
    assert_eq!(format!("{}", fbig!(-0x1p-4)), "-0.0001");

    assert_eq!(format!("{}", FBin::INFINITY), "inf");
    assert_eq!(format!("{}", FBin::NEG_INFINITY), "-inf");
    assert_eq!(format!("{}", FBin::from_parts(i8::MAX.into(), -4)), "111.1111");
    assert_eq!(format!("{}", FBin::from_parts(i8::MIN.into(), -4)), "-1000");
    assert_eq!(format!("{}", FBin::from_parts(i16::MAX.into(), -8)), "1111111.11111111");
    assert_eq!(format!("{}", FBin::from_parts(i16::MIN.into(), -8)), "-10000000");

    assert_eq!(format!("{:.0}", fbig!(0x0)), "0");
    assert_eq!(format!("{:.0}", fbig!(0x1)), "1");
    assert_eq!(format!("{:.0}", fbig!(-0x1)), "-1");
    assert_eq!(format!("{:.0}", fbig!(0x1p4)), "10000");
    assert_eq!(format!("{:.0}", fbig!(-0x1p4)), "-10000");
    assert_eq!(format!("{:.0}", fbig!(0x1p-1)), "0");
    assert_eq!(format!("{:.0}", fbig!(-0x1p-1)), "-0");
    assert_eq!(format!("{:.0}", fbig!(0x1p-4)), "0");
    assert_eq!(format!("{:.0}", fbig!(-0x1p-4)), "-0");
    assert_eq!(format!("{:8.0}", fbig!(0x0)), "       0");
    assert_eq!(format!("{:8.0}", fbig!(0x1)), "       1");
    assert_eq!(format!("{:8.0}", fbig!(-0x1)), "      -1");
    assert_eq!(format!("{:8.0}", fbig!(0x1p4)), "   10000");
    assert_eq!(format!("{:8.0}", fbig!(-0x1p4)), "  -10000");
    assert_eq!(format!("{:8.0}", fbig!(0x1p-1)), "       0");
    assert_eq!(format!("{:8.0}", fbig!(-0x1p-1)), "      -0");
    assert_eq!(format!("{:8.0}", fbig!(0x1p-4)), "       0");
    assert_eq!(format!("{:8.0}", fbig!(-0x1p-4)), "      -0");

    assert_eq!(format!("{:.8}", fbig!(0x0)), "0.00000000");
    assert_eq!(format!("{:.8}", fbig!(0x1)), "1.00000000");
    assert_eq!(format!("{:.8}", fbig!(-0x1)), "-1.00000000");
    assert_eq!(format!("{:.8}", fbig!(0x1p4)), "10000.00000000");
    assert_eq!(format!("{:.8}", fbig!(-0x1p4)), "-10000.00000000");
    assert_eq!(format!("{:.8}", fbig!(0x1p-1)), "0.10000000");
    assert_eq!(format!("{:.8}", fbig!(-0x1p-1)), "-0.10000000");
    assert_eq!(format!("{:.8}", fbig!(0x1p-4)), "0.00010000");
    assert_eq!(format!("{:.8}", fbig!(-0x1p-4)), "-0.00010000");
    assert_eq!(format!("{:8.4}", fbig!(0x0)), "  0.0000");
    assert_eq!(format!("{:8.4}", fbig!(0x1)), "  1.0000");
    assert_eq!(format!("{:8.4}", fbig!(-0x1)), " -1.0000");
    assert_eq!(format!("{:8.4}", fbig!(0x1p4)), "10000.0000");
    assert_eq!(format!("{:8.4}", fbig!(-0x1p4)), "-10000.0000");
    assert_eq!(format!("{:8.4}", fbig!(0x1p-1)), "  0.1000");
    assert_eq!(format!("{:8.4}", fbig!(-0x1p-1)), " -0.1000");
    assert_eq!(format!("{:8.4}", fbig!(0x1p-4)), "  0.0001");
    assert_eq!(format!("{:8.4}", fbig!(-0x1p-4)), " -0.0001");
    assert_eq!(format!("{:8.4}", fbig!(0x1p-5)), "  0.0000");
    assert_eq!(format!("{:8.4}", fbig!(-0x1p-5)), " -0.0000");

    assert_eq!(format!("{:16}", fbig!(0x123p-4)), "      10010.0011");
    assert_eq!(format!("{:16}", fbig!(-0x123p-4)), "     -10010.0011");
    assert_eq!(format!("{:+16}", fbig!(0x123p-4)), "     +10010.0011");
    assert_eq!(format!("{:+16}", fbig!(-0x123p-4)), "     -10010.0011");
    assert_eq!(format!("{:<16}", fbig!(0x123p-4)), "10010.0011      ");
    assert_eq!(format!("{:<16}", fbig!(-0x123p-4)), "-10010.0011     ");
    assert_eq!(format!("{:<+16}", fbig!(0x123p-4)), "+10010.0011     ");
    assert_eq!(format!("{:^16}", fbig!(0x123p-4)), "   10010.0011   ");
    assert_eq!(format!("{:^16}", fbig!(-0x123p-4)), "  -10010.0011   ");
    assert_eq!(format!("{:^+16}", fbig!(0x123p-4)), "  +10010.0011   ");
    assert_eq!(format!("{:>16}", fbig!(0x123p-4)), "      10010.0011");
    assert_eq!(format!("{:>16}", fbig!(-0x123p-4)), "     -10010.0011");
    assert_eq!(format!("{:>+16}", fbig!(0x123p-4)), "     +10010.0011");
    assert_eq!(format!("{:=<16}", fbig!(-0x123p-4)), "-10010.0011=====");
    assert_eq!(format!("{:=^16}", fbig!(-0x123p-4)), "==-10010.0011===");
    assert_eq!(format!("{:=>16}", fbig!(-0x123p-4)), "=====-10010.0011");
    assert_eq!(format!("{:=<+16}", fbig!(0x123p-4)), "+10010.0011=====");
    assert_eq!(format!("{:=^+16}", fbig!(0x123p-4)), "==+10010.0011===");
    assert_eq!(format!("{:=>+16}", fbig!(0x123p-4)), "=====+10010.0011");

    assert_eq!(format!("{:16.0}", fbig!(0x123p-4)), "           10010");
    assert_eq!(format!("{:16.0}", fbig!(-0x123p-4)), "          -10010");
    assert_eq!(format!("{:+16.0}", fbig!(0x123p-4)), "          +10010");
    assert_eq!(format!("{:+16.0}", fbig!(-0x123p-4)), "          -10010");
    assert_eq!(format!("{:<16.0}", fbig!(0x123p-4)), "10010           ");
    assert_eq!(format!("{:<16.0}", fbig!(-0x123p-4)), "-10010          ");
    assert_eq!(format!("{:<+16.0}", fbig!(0x123p-4)), "+10010          ");
    assert_eq!(format!("{:^16.0}", fbig!(0x123p-4)), "     10010      ");
    assert_eq!(format!("{:^16.0}", fbig!(-0x123p-4)), "     -10010     ");
    assert_eq!(format!("{:^+16.0}", fbig!(0x123p-4)), "     +10010     ");
    assert_eq!(format!("{:>16.0}", fbig!(0x123p-4)), "           10010");
    assert_eq!(format!("{:>16.0}", fbig!(-0x123p-4)), "          -10010");
    assert_eq!(format!("{:>+16.0}", fbig!(0x123p-4)), "          +10010");
    assert_eq!(format!("{:=<16.0}", fbig!(-0x123p-4)), "-10010==========");
    assert_eq!(format!("{:=^16.0}", fbig!(-0x123p-4)), "=====-10010=====");
    assert_eq!(format!("{:=>16.0}", fbig!(-0x123p-4)), "==========-10010");
    assert_eq!(format!("{:=<+16.0}", fbig!(0x123p-4)), "+10010==========");
    assert_eq!(format!("{:=^+16.0}", fbig!(0x123p-4)), "=====+10010=====");
    assert_eq!(format!("{:=>+16.0}", fbig!(0x123p-4)), "==========+10010");

    assert_eq!(format!("{:16.8}", fbig!(0x123p-4)), "  10010.00110000");
    assert_eq!(format!("{:16.8}", fbig!(-0x123p-4)), " -10010.00110000");
    assert_eq!(format!("{:+16.8}", fbig!(0x123p-4)), " +10010.00110000");
    assert_eq!(format!("{:+16.8}", fbig!(-0x123p-4)), " -10010.00110000");
    assert_eq!(format!("{:<16.8}", fbig!(0x123p-4)), "10010.00110000  ");
    assert_eq!(format!("{:<16.8}", fbig!(-0x123p-4)), "-10010.00110000 ");
    assert_eq!(format!("{:<+16.8}", fbig!(0x123p-4)), "+10010.00110000 ");
    assert_eq!(format!("{:^16.8}", fbig!(0x123p-4)), " 10010.00110000 ");
    assert_eq!(format!("{:^16.8}", fbig!(-0x123p-4)), "-10010.00110000 ");
    assert_eq!(format!("{:^+16.8}", fbig!(0x123p-4)), "+10010.00110000 ");
    assert_eq!(format!("{:>16.8}", fbig!(0x123p-4)), "  10010.00110000");
    assert_eq!(format!("{:>16.8}", fbig!(-0x123p-4)), " -10010.00110000");
    assert_eq!(format!("{:>+16.8}", fbig!(0x123p-4)), " +10010.00110000");
    assert_eq!(format!("{:=<16.8}", fbig!(-0x123p-4)), "-10010.00110000=");
    assert_eq!(format!("{:=^16.8}", fbig!(-0x123p-4)), "-10010.00110000=");
    assert_eq!(format!("{:=>16.8}", fbig!(-0x123p-4)), "=-10010.00110000");
    assert_eq!(format!("{:=<+16.8}", fbig!(0x123p-4)), "+10010.00110000=");
    assert_eq!(format!("{:=^+16.8}", fbig!(0x123p-4)), "+10010.00110000=");
    assert_eq!(format!("{:=>+16.8}", fbig!(0x123p-4)), "=+10010.00110000");
}

#[test]
fn test_format_decimal() {
    assert_eq!(format!("{}", dbig!(0)), "0");
    assert_eq!(format!("{}", dbig!(1)), "1");
    assert_eq!(format!("{}", dbig!(-1)), "-1");
    assert_eq!(format!("{}", dbig!(1e4)), "10000");
    assert_eq!(format!("{}", dbig!(-1e4)), "-10000");
    assert_eq!(format!("{}", dbig!(1e-1)), "0.1");
    assert_eq!(format!("{}", dbig!(-1e-1)), "-0.1");
    assert_eq!(format!("{}", dbig!(1e-4)), "0.0001");
    assert_eq!(format!("{}", dbig!(-1e-4)), "-0.0001");

    assert_eq!(format!("{}", DBig::INFINITY), "inf");
    assert_eq!(format!("{}", DBig::NEG_INFINITY), "-inf");
    assert_eq!(format!("{}", DBig::from_parts(i8::MAX.into(), -1)), "12.7");
    assert_eq!(format!("{}", DBig::from_parts(i8::MIN.into(), -1)), "-12.8");
    assert_eq!(format!("{}", DBig::from_parts(i16::MAX.into(), -2)), "327.67");
    assert_eq!(format!("{}", DBig::from_parts(i16::MIN.into(), -2)), "-327.68");

    assert_eq!(format!("{:.0}", dbig!(0)), "0");
    assert_eq!(format!("{:.0}", dbig!(1)), "1");
    assert_eq!(format!("{:.0}", dbig!(-1)), "-1");
    assert_eq!(format!("{:.0}", dbig!(1e4)), "10000");
    assert_eq!(format!("{:.0}", dbig!(-1e4)), "-10000");
    assert_eq!(format!("{:.0}", dbig!(1e-1)), "0");
    assert_eq!(format!("{:.0}", dbig!(-1e-1)), "-0");
    assert_eq!(format!("{:.0}", dbig!(1e-4)), "0");
    assert_eq!(format!("{:.0}", dbig!(-1e-4)), "-0");
    assert_eq!(format!("{:.0}", dbig!(9e-1)), "1"); // round up
    assert_eq!(format!("{:.0}", dbig!(-9e-1)), "-1");
    assert_eq!(format!("{:.0}", dbig!(99e-1)), "10");
    assert_eq!(format!("{:.0}", dbig!(-99e-1)), "-10");
    assert_eq!(format!("{:8.0}", dbig!(0)), "       0");
    assert_eq!(format!("{:8.0}", dbig!(1)), "       1");
    assert_eq!(format!("{:8.0}", dbig!(-1)), "      -1");
    assert_eq!(format!("{:8.0}", dbig!(1e4)), "   10000");
    assert_eq!(format!("{:8.0}", dbig!(-1e4)), "  -10000");
    assert_eq!(format!("{:8.0}", dbig!(1e-1)), "       0");
    assert_eq!(format!("{:8.0}", dbig!(-1e-1)), "      -0");
    assert_eq!(format!("{:8.0}", dbig!(1e-4)), "       0");
    assert_eq!(format!("{:8.0}", dbig!(-1e-4)), "      -0");
    assert_eq!(format!("{:8.0}", dbig!(9e-1)), "       1");
    assert_eq!(format!("{:8.0}", dbig!(-9e-1)), "      -1");
    assert_eq!(format!("{:8.0}", dbig!(99e-1)), "      10");
    assert_eq!(format!("{:8.0}", dbig!(-99e-1)), "     -10");

    assert_eq!(format!("{:.8}", dbig!(0)), "0.00000000");
    assert_eq!(format!("{:.8}", dbig!(1)), "1.00000000");
    assert_eq!(format!("{:.8}", dbig!(-1)), "-1.00000000");
    assert_eq!(format!("{:.8}", dbig!(1e4)), "10000.00000000");
    assert_eq!(format!("{:.8}", dbig!(-1e4)), "-10000.00000000");
    assert_eq!(format!("{:.8}", dbig!(1e-1)), "0.10000000");
    assert_eq!(format!("{:.8}", dbig!(-1e-1)), "-0.10000000");
    assert_eq!(format!("{:.8}", dbig!(1e-4)), "0.00010000");
    assert_eq!(format!("{:.8}", dbig!(-1e-4)), "-0.00010000");
    assert_eq!(format!("{:8.4}", dbig!(0)), "  0.0000");
    assert_eq!(format!("{:8.4}", dbig!(1)), "  1.0000");
    assert_eq!(format!("{:8.4}", dbig!(-1)), " -1.0000");
    assert_eq!(format!("{:8.4}", dbig!(1e4)), "10000.0000");
    assert_eq!(format!("{:8.4}", dbig!(-1e4)), "-10000.0000");
    assert_eq!(format!("{:8.4}", dbig!(1e-1)), "  0.1000");
    assert_eq!(format!("{:8.4}", dbig!(-1e-1)), " -0.1000");
    assert_eq!(format!("{:8.4}", dbig!(1e-4)), "  0.0001");
    assert_eq!(format!("{:8.4}", dbig!(-1e-4)), " -0.0001");
    assert_eq!(format!("{:8.4}", dbig!(1e-5)), "  0.0000");
    assert_eq!(format!("{:8.4}", dbig!(-1e-5)), " -0.0000");
    assert_eq!(format!("{:8.4}", dbig!(9e-5)), "  0.0001");
    assert_eq!(format!("{:8.4}", dbig!(-9e-5)), " -0.0001");
    assert_eq!(format!("{:8.4}", dbig!(99e-5)), "  0.0010");
    assert_eq!(format!("{:8.4}", dbig!(-99e-5)), " -0.0010");

    assert_eq!(format!("{:8}", dbig!(123e-2)), "    1.23");
    assert_eq!(format!("{:8}", dbig!(-123e-2)), "   -1.23");
    assert_eq!(format!("{:+8}", dbig!(123e-2)), "   +1.23");
    assert_eq!(format!("{:+8}", dbig!(-123e-2)), "   -1.23");
    assert_eq!(format!("{:<8}", dbig!(123e-2)), "1.23    ");
    assert_eq!(format!("{:<8}", dbig!(-123e-2)), "-1.23   ");
    assert_eq!(format!("{:<+8}", dbig!(123e-2)), "+1.23   ");
    assert_eq!(format!("{:^8}", dbig!(123e-2)), "  1.23  ");
    assert_eq!(format!("{:^8}", dbig!(-123e-2)), " -1.23  ");
    assert_eq!(format!("{:^+8}", dbig!(123e-2)), " +1.23  ");
    assert_eq!(format!("{:>8}", dbig!(123e-2)), "    1.23");
    assert_eq!(format!("{:>8}", dbig!(-123e-2)), "   -1.23");
    assert_eq!(format!("{:>+8}", dbig!(123e-2)), "   +1.23");
    assert_eq!(format!("{:=<8}", dbig!(-123e-2)), "-1.23===");
    assert_eq!(format!("{:=^8}", dbig!(-123e-2)), "=-1.23==");
    assert_eq!(format!("{:=>8}", dbig!(-123e-2)), "===-1.23");
    assert_eq!(format!("{:=<+8}", dbig!(123e-2)), "+1.23===");
    assert_eq!(format!("{:=^+8}", dbig!(123e-2)), "=+1.23==");
    assert_eq!(format!("{:=>+8}", dbig!(123e-2)), "===+1.23");

    assert_eq!(format!("{:8.0}", dbig!(123e-2)), "       1");
    assert_eq!(format!("{:8.0}", dbig!(-123e-2)), "      -1");
    assert_eq!(format!("{:+8.0}", dbig!(123e-2)), "      +1");
    assert_eq!(format!("{:+8.0}", dbig!(-123e-2)), "      -1");
    assert_eq!(format!("{:<8.0}", dbig!(123e-2)), "1       ");
    assert_eq!(format!("{:<8.0}", dbig!(-123e-2)), "-1      ");
    assert_eq!(format!("{:<+8.0}", dbig!(123e-2)), "+1      ");
    assert_eq!(format!("{:^8.0}", dbig!(123e-2)), "   1    ");
    assert_eq!(format!("{:^8.0}", dbig!(-123e-2)), "   -1   ");
    assert_eq!(format!("{:^+8.0}", dbig!(123e-2)), "   +1   ");
    assert_eq!(format!("{:>8.0}", dbig!(123e-2)), "       1");
    assert_eq!(format!("{:>8.0}", dbig!(-123e-2)), "      -1");
    assert_eq!(format!("{:>+8.0}", dbig!(123e-2)), "      +1");
    assert_eq!(format!("{:=<8.0}", dbig!(-123e-2)), "-1======");
    assert_eq!(format!("{:=^8.0}", dbig!(-123e-2)), "===-1===");
    assert_eq!(format!("{:=>8.0}", dbig!(-123e-2)), "======-1");
    assert_eq!(format!("{:=<+8.0}", dbig!(123e-2)), "+1======");
    assert_eq!(format!("{:=^+8.0}", dbig!(123e-2)), "===+1===");
    assert_eq!(format!("{:=>+8.0}", dbig!(123e-2)), "======+1");

    assert_eq!(format!("{:8.4}", dbig!(123e-2)), "  1.2300");
    assert_eq!(format!("{:8.4}", dbig!(-123e-2)), " -1.2300");
    assert_eq!(format!("{:+8.4}", dbig!(123e-2)), " +1.2300");
    assert_eq!(format!("{:+8.4}", dbig!(-123e-2)), " -1.2300");
    assert_eq!(format!("{:<8.4}", dbig!(123e-2)), "1.2300  ");
    assert_eq!(format!("{:<8.4}", dbig!(-123e-2)), "-1.2300 ");
    assert_eq!(format!("{:<+8.4}", dbig!(123e-2)), "+1.2300 ");
    assert_eq!(format!("{:^8.4}", dbig!(123e-2)), " 1.2300 ");
    assert_eq!(format!("{:^8.4}", dbig!(-123e-2)), "-1.2300 ");
    assert_eq!(format!("{:^+8.4}", dbig!(123e-2)), "+1.2300 ");
    assert_eq!(format!("{:>8.4}", dbig!(123e-2)), "  1.2300");
    assert_eq!(format!("{:>8.4}", dbig!(-123e-2)), " -1.2300");
    assert_eq!(format!("{:>+8.4}", dbig!(123e-2)), " +1.2300");
    assert_eq!(format!("{:=<8.4}", dbig!(-123e-2)), "-1.2300=");
    assert_eq!(format!("{:=^8.4}", dbig!(-123e-2)), "-1.2300=");
    assert_eq!(format!("{:=>8.4}", dbig!(-123e-2)), "=-1.2300");
    assert_eq!(format!("{:=<+8.4}", dbig!(123e-2)), "+1.2300=");
    assert_eq!(format!("{:=^+8.4}", dbig!(123e-2)), "+1.2300=");
    assert_eq!(format!("{:=>+8.4}", dbig!(123e-2)), "=+1.2300");
}

#[test]
#[rustfmt::skip::macros(fbig)]
fn test_format_debug() {
    assert_eq!(format!("{:?}", DBig::INFINITY), "inf");
    assert_eq!(format!("{:?}", DBig::NEG_INFINITY), "-inf");
    assert_eq!(format!("{:#?}", DBig::INFINITY), "inf");
    assert_eq!(format!("{:#?}", DBig::NEG_INFINITY), "-inf");

    assert_eq!(format!("{:?}", fbig!(0x1234p-4).repr()), "1165 * 2 ^ -2");
    assert_eq!(
        format!("{:?}", fbig!(0x1234p-4).context()),
        "Context { precision: 16, rounding: Zero }"
    );
    assert_eq!(format!("{:?}", fbig!(0x1234p-4)), "1165 * 2 ^ -2 (prec: 16)");

    assert_eq!(
        format!("{:#?}", fbig!(0x1234p-4).repr()),
        r#"Repr {
    significand: 1165 (11 bits),
    exponent: 2 ^ -2,
}"#
    );
    assert_eq!(
        format!("{:#?}", fbig!(0x1234p-4).context()),
        r#"Context {
    precision: 16,
    rounding: Zero,
}"#
    );
    assert_eq!(
        format!("{:#?}", fbig!(0x1234p-4)),
        r#"FBig {
    significand: 1165 (11 bits),
    exponent: 2 ^ -2,
    precision: 16,
    rounding: Zero,
}"#
    );

    assert_eq!(format!("{:?}", dbig!(1234e-2).repr()), "1234 * 10 ^ -2");
    assert_eq!(
        format!("{:?}", dbig!(1234e-2).context()),
        "Context { precision: 4, rounding: HalfAway }"
    );
    assert_eq!(format!("{:?}", dbig!(1234e-2)), "1234 * 10 ^ -2 (prec: 4)");

    assert_eq!(
        format!("{:#?}", dbig!(1234e-2).repr()),
        r#"Repr {
    significand: 1234 (4 digits, 11 bits),
    exponent: 10 ^ -2,
}"#
    );
    assert_eq!(
        format!("{:#?}", dbig!(1234e-2).context()),
        r#"Context {
    precision: 4,
    rounding: HalfAway,
}"#
    );
    assert_eq!(
        format!("{:#?}", dbig!(1234e-2)),
        r#"FBig {
    significand: 1234 (4 digits, 11 bits),
    exponent: 10 ^ -2,
    precision: 4,
    rounding: HalfAway,
}"#
    );
}