File: test_cpp_bin_float.cpp

package info (click to toggle)
boost1.90 1.90.0-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 593,120 kB
  • sloc: cpp: 4,190,908; xml: 196,648; python: 34,618; ansic: 23,145; asm: 5,468; sh: 3,774; makefile: 1,161; perl: 1,020; sql: 728; ruby: 676; yacc: 478; java: 77; lisp: 24; csh: 6
file content (930 lines) | stat: -rw-r--r-- 47,517 bytes parent folder | download | duplicates (3)
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
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
// Copyright John Maddock 2013.

// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifdef _MSC_VER
#define _SCL_SECURE_NO_WARNINGS
#endif

#include <boost/multiprecision/cpp_bin_float.hpp>
#ifdef TEST_MPFR
#include <boost/multiprecision/mpfr.hpp>
#endif
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
#include "test.hpp"
#include <iostream>
#include <iomanip>

template <class T>
T generate_random()
{
   typedef int                   e_type;
   static boost::random::mt19937 gen;
   T                             val      = gen();
   T                             prev_val = -1;
   while (val != prev_val)
   {
      val *= (gen.max)();
      prev_val = val;
      val += gen();
   }
   e_type e;
   val = frexp(val, &e);

   static boost::random::uniform_int_distribution<e_type> ui(-20, 20);
   return ldexp(val, ui(gen));
}

using namespace boost::multiprecision;
#ifdef TEST_MPFR
typedef number<mpfr_float_backend<35> > good_type;
#else
typedef double good_type;
#endif
typedef number<cpp_bin_float<std::numeric_limits<good_type>::digits, digit_base_2>, et_off> test_type;

void test_special_cases()
{
#if !defined(BOOST_CI_ASAN_BUILD) && !defined(BOOST_CI_USAN_BUID)
   test_type max_val        = (std::numeric_limits<test_type>::max)();
   test_type denorm_min_val = std::numeric_limits<test_type>::denorm_min();
   test_type min_val        = (std::numeric_limits<test_type>::min)();
   test_type eps            = std::numeric_limits<test_type>::epsilon();
   test_type inf_val        = (std::numeric_limits<test_type>::infinity)();
   test_type nan_val        = (std::numeric_limits<test_type>::quiet_NaN)();
   test_type half           = 0.5;
   test_type one_point_5    = 1.5;

   BOOST_CHECK((boost::math::isnormal)(max_val));
   BOOST_CHECK((boost::math::isnormal)(-max_val));
   BOOST_CHECK((boost::math::isnormal)(min_val));
   BOOST_CHECK((boost::math::isnormal)(-min_val));
   BOOST_CHECK((boost::math::isnormal)(denorm_min_val));
   BOOST_CHECK((boost::math::isnormal)(-denorm_min_val));
   BOOST_CHECK((boost::math::isinf)(inf_val));
   BOOST_CHECK((boost::math::isinf)(-inf_val));
   BOOST_CHECK((boost::math::isnan)(nan_val));
   BOOST_CHECK((boost::math::isnan)(-nan_val));

   if (!std::numeric_limits<test_type>::has_denorm) {
      BOOST_CHECK_EQUAL(denorm_min_val, min_val);
   } else {
      BOOST_CHECK_LE(denorm_min_val, min_val);
   }

   // Adding epsilon will increment 1.0:
   BOOST_CHECK(test_type(1) + eps != test_type(1));
   BOOST_CHECK(test_type(1) + eps / 2 == test_type(1));
   // But it's not the smallest value that will do that:
   test_type small = 1 + eps;
   small           = ldexp(small, -std::numeric_limits<test_type>::digits);
   BOOST_CHECK(test_type(1) + small != test_type(1));
   // And if we increment 1.0 first, then an even smaller
   // addition will round up:
   test_type one_next = test_type(1) + eps;
   BOOST_CHECK(one_next + eps / 2 != one_next);

   // Overflow:
   BOOST_CHECK_EQUAL(max_val + max_val * eps, inf_val);
   BOOST_CHECK_EQUAL(-max_val - max_val * eps, -inf_val);
   BOOST_CHECK_EQUAL(max_val * 2, inf_val);
   BOOST_CHECK_EQUAL(max_val * -2, -inf_val);
   BOOST_CHECK_EQUAL(max_val / half, inf_val);
   BOOST_CHECK_EQUAL(max_val / -half, -inf_val);
   BOOST_CHECK_EQUAL(max_val / min_val, inf_val);
   BOOST_CHECK_EQUAL(max_val / -min_val, -inf_val);
   BOOST_CHECK_EQUAL(max_val / denorm_min_val, inf_val);
   BOOST_CHECK_EQUAL(max_val / -denorm_min_val, -inf_val);
   // Underflow:
   BOOST_CHECK_EQUAL(min_val * 2 - one_point_5 * min_val, 0);
   BOOST_CHECK_EQUAL(-min_val * 2 + one_point_5 * min_val, 0);
   BOOST_CHECK_EQUAL(min_val / 2, 0);
   BOOST_CHECK_EQUAL(min_val / max_val, 0);
   BOOST_CHECK_EQUAL(min_val * half, 0);
   BOOST_CHECK_EQUAL(min_val - min_val, 0);
   BOOST_CHECK_EQUAL(-min_val + min_val, 0);

   BOOST_CHECK_EQUAL(denorm_min_val * 2 - one_point_5 * denorm_min_val, 0);
   BOOST_CHECK_EQUAL(-denorm_min_val * 2 + one_point_5 * denorm_min_val, 0);
   BOOST_CHECK_EQUAL(denorm_min_val / 2, 0);
   BOOST_CHECK_EQUAL(denorm_min_val / max_val, 0);
   BOOST_CHECK_EQUAL(denorm_min_val * half, 0);
   BOOST_CHECK_EQUAL(denorm_min_val - denorm_min_val, 0);
   BOOST_CHECK_EQUAL(-denorm_min_val + denorm_min_val, 0);
   // Things which should not over/underflow:
   BOOST_CHECK_EQUAL((min_val * 2) / 2, min_val);
   BOOST_CHECK_GE((min_val * 2.0000001) / 1.9999999999999999, min_val);
   BOOST_CHECK_EQUAL(min_val * 2 - min_val, min_val);

   BOOST_CHECK_EQUAL((denorm_min_val * 2) / 2, denorm_min_val);
   BOOST_CHECK_GE((denorm_min_val * 2.0000001) / 1.9999999999999999, denorm_min_val);
   BOOST_CHECK_EQUAL(denorm_min_val * 2 - denorm_min_val, denorm_min_val);

   BOOST_CHECK_EQUAL(-max_val + max_val, 0);
   BOOST_CHECK_EQUAL(max_val - max_val, 0);
   BOOST_CHECK_EQUAL((max_val / 2) * 2, max_val);
   BOOST_CHECK_LE((max_val / 2.0000001) * 1.9999999999999999, max_val);
   BOOST_CHECK_EQUAL(max_val / 2 + max_val / 2, max_val);

   // Things involving zero:
   BOOST_CHECK_EQUAL(max_val + 0, max_val);
   BOOST_CHECK_EQUAL(max_val - 0, max_val);
   BOOST_CHECK_EQUAL(0 + max_val, max_val);
   BOOST_CHECK_EQUAL(0 - max_val, -max_val);
   BOOST_CHECK_EQUAL(max_val * 0, 0);
   BOOST_CHECK_EQUAL(0 * max_val, 0);
   BOOST_CHECK_EQUAL(max_val / 0, inf_val);
   BOOST_CHECK_EQUAL(0 / max_val, 0);
   BOOST_CHECK_EQUAL(-max_val / 0, -inf_val);
   BOOST_CHECK_EQUAL(0 / -max_val, 0);
   // Things involving infinity:
   BOOST_CHECK_EQUAL(inf_val + 2, inf_val);
   BOOST_CHECK_EQUAL(inf_val - 2, inf_val);
   BOOST_CHECK_EQUAL(inf_val + -2, inf_val);
   BOOST_CHECK_EQUAL(inf_val - -2, inf_val);
   BOOST_CHECK_EQUAL(-inf_val + 2, -inf_val);
   BOOST_CHECK_EQUAL(-inf_val - 2, -inf_val);
   BOOST_CHECK_EQUAL(-inf_val + -2, -inf_val);
   BOOST_CHECK_EQUAL(-inf_val - -2, -inf_val);

   BOOST_CHECK_EQUAL(2 + inf_val, inf_val);
   BOOST_CHECK_EQUAL(2 - inf_val, -inf_val);
   BOOST_CHECK_EQUAL(-2 + inf_val, inf_val);
   BOOST_CHECK_EQUAL(-2 - inf_val, -inf_val);
   BOOST_CHECK_EQUAL(2 + (-inf_val), -inf_val);
   BOOST_CHECK_EQUAL(2 - (-inf_val), inf_val);
   BOOST_CHECK_EQUAL(-2 + (-inf_val), -inf_val);
   BOOST_CHECK_EQUAL(-2 - (-inf_val), inf_val);

   BOOST_CHECK_EQUAL(sqrt(inf_val), inf_val);
   BOOST_CHECK(boost::math::isnan(sqrt(-inf_val)));

   BOOST_CHECK_EQUAL(inf_val + test_type(2), inf_val);
   BOOST_CHECK_EQUAL(inf_val - test_type(2), inf_val);
   BOOST_CHECK_EQUAL(inf_val + test_type(-2), inf_val);
   BOOST_CHECK_EQUAL(inf_val - test_type(-2), inf_val);
   BOOST_CHECK_EQUAL(-inf_val + test_type(2), -inf_val);
   BOOST_CHECK_EQUAL(-inf_val - test_type(2), -inf_val);
   BOOST_CHECK_EQUAL(-inf_val + test_type(-2), -inf_val);
   BOOST_CHECK_EQUAL(-inf_val - test_type(-2), -inf_val);

   BOOST_CHECK_EQUAL(test_type(2) + inf_val, inf_val);
   BOOST_CHECK_EQUAL(test_type(2) - inf_val, -inf_val);
   BOOST_CHECK_EQUAL(test_type(-2) + inf_val, inf_val);
   BOOST_CHECK_EQUAL(test_type(-2) - inf_val, -inf_val);
   BOOST_CHECK_EQUAL(test_type(2) + (-inf_val), -inf_val);
   BOOST_CHECK_EQUAL(test_type(2) - (-inf_val), inf_val);
   BOOST_CHECK_EQUAL(test_type(-2) + (-inf_val), -inf_val);
   BOOST_CHECK_EQUAL(test_type(-2) - (-inf_val), inf_val);

   BOOST_CHECK((boost::math::isnan)(inf_val - inf_val));
   BOOST_CHECK_EQUAL(inf_val * 2, inf_val);
   BOOST_CHECK_EQUAL(-inf_val * 2, -inf_val);
   BOOST_CHECK_EQUAL(inf_val * -2, -inf_val);
   BOOST_CHECK_EQUAL(-inf_val * -2, inf_val);
   BOOST_CHECK_EQUAL(inf_val * test_type(-2), -inf_val);
   BOOST_CHECK_EQUAL(-inf_val * test_type(-2), inf_val);
   BOOST_CHECK((boost::math::isnan)(inf_val * 0));
   BOOST_CHECK((boost::math::isnan)(-inf_val * 0));
   BOOST_CHECK_EQUAL(inf_val / 2, inf_val);
   BOOST_CHECK_EQUAL(-inf_val / 2, -inf_val);
   BOOST_CHECK_EQUAL(inf_val / -2, -inf_val);
   BOOST_CHECK_EQUAL(-inf_val / -2, inf_val);
   BOOST_CHECK_EQUAL(inf_val / test_type(-2), -inf_val);
   BOOST_CHECK_EQUAL(-inf_val / test_type(-2), inf_val);
   BOOST_CHECK_EQUAL(inf_val / 0, inf_val);
   BOOST_CHECK_EQUAL(-inf_val / 0, -inf_val);
   BOOST_CHECK((boost::math::isnan)(inf_val / inf_val));
   BOOST_CHECK((boost::math::isnan)(-inf_val / inf_val));
   // Things involving nan:
   BOOST_CHECK((boost::math::isnan)(nan_val + 2));
   BOOST_CHECK((boost::math::isnan)(nan_val - 2));
   BOOST_CHECK((boost::math::isnan)(nan_val + 0));
   BOOST_CHECK((boost::math::isnan)(nan_val - 0));
   BOOST_CHECK((boost::math::isnan)(nan_val + inf_val));
   BOOST_CHECK((boost::math::isnan)(nan_val - inf_val));
   BOOST_CHECK((boost::math::isnan)(nan_val + nan_val));
   BOOST_CHECK((boost::math::isnan)(nan_val - nan_val));
   BOOST_CHECK((boost::math::isnan)(2 + nan_val));
   BOOST_CHECK((boost::math::isnan)(2 - nan_val));
   BOOST_CHECK((boost::math::isnan)(0 - nan_val));
   BOOST_CHECK((boost::math::isnan)(0 - nan_val));
   BOOST_CHECK((boost::math::isnan)(inf_val + nan_val));
   BOOST_CHECK((boost::math::isnan)(inf_val - nan_val));
   BOOST_CHECK((boost::math::isnan)(nan_val * 2));
   BOOST_CHECK((boost::math::isnan)(nan_val / 2));
   BOOST_CHECK((boost::math::isnan)(nan_val * 0));
   BOOST_CHECK((boost::math::isnan)(nan_val / 0));
   BOOST_CHECK((boost::math::isnan)(nan_val * inf_val));
   BOOST_CHECK((boost::math::isnan)(nan_val / inf_val));
   BOOST_CHECK((boost::math::isnan)(nan_val * nan_val));
   BOOST_CHECK((boost::math::isnan)(nan_val / nan_val));
   BOOST_CHECK((boost::math::isnan)(2 * nan_val));
   BOOST_CHECK((boost::math::isnan)(2 / nan_val));
   BOOST_CHECK((boost::math::isnan)(0 / nan_val));
   BOOST_CHECK((boost::math::isnan)(0 / nan_val));
   BOOST_CHECK((boost::math::isnan)(inf_val * nan_val));
   BOOST_CHECK((boost::math::isnan)(inf_val / nan_val));
   // Corner cases:
   BOOST_CHECK_EQUAL((max_val * half) / half, max_val);
   BOOST_CHECK_EQUAL((max_val / 2) * 2, max_val);

   BOOST_CHECK_EQUAL((min_val / half) * half, min_val);
   BOOST_CHECK_EQUAL((min_val * 2) / 2, min_val);
   BOOST_CHECK_EQUAL(max_val + min_val, max_val);
   BOOST_CHECK_EQUAL(min_val + max_val, max_val);
   BOOST_CHECK_EQUAL(max_val - min_val, max_val);
   BOOST_CHECK_EQUAL(min_val - max_val, -max_val);

   BOOST_CHECK_EQUAL((denorm_min_val / half) * half, denorm_min_val);
   BOOST_CHECK_EQUAL((denorm_min_val * 2) / 2, denorm_min_val);
   BOOST_CHECK_EQUAL(max_val + denorm_min_val, max_val);
   BOOST_CHECK_EQUAL(denorm_min_val + max_val, max_val);
   BOOST_CHECK_EQUAL(max_val - denorm_min_val, max_val);
   BOOST_CHECK_EQUAL(denorm_min_val - max_val, -max_val);
   // Signed zeros:
   BOOST_CHECK(boost::math::signbit(min_val * -min_val));
   BOOST_CHECK(boost::math::signbit(min_val * min_val) == 0);
   BOOST_CHECK(boost::math::signbit(-min_val * -min_val) == 0);
   BOOST_CHECK(boost::math::signbit(-min_val * min_val));
   BOOST_CHECK(boost::math::signbit(min_val / max_val) == 0);
   BOOST_CHECK(boost::math::signbit(min_val / -max_val));
   BOOST_CHECK(boost::math::signbit(-min_val / -max_val) == 0);
   BOOST_CHECK(boost::math::signbit(-min_val / max_val));
   BOOST_CHECK(boost::math::signbit(min_val / 2) == 0);
   BOOST_CHECK(boost::math::signbit(min_val / -2));
   BOOST_CHECK(boost::math::signbit(-min_val / -2) == 0);
   BOOST_CHECK(boost::math::signbit(-min_val / 2));
   test_type neg_zero = min_val * -min_val;

   BOOST_CHECK(boost::math::signbit(denorm_min_val * -denorm_min_val));
   BOOST_CHECK(boost::math::signbit(denorm_min_val * denorm_min_val) == 0);
   BOOST_CHECK(boost::math::signbit(-denorm_min_val * -denorm_min_val) == 0);
   BOOST_CHECK(boost::math::signbit(-denorm_min_val * denorm_min_val));
   BOOST_CHECK(boost::math::signbit(denorm_min_val / max_val) == 0);
   BOOST_CHECK(boost::math::signbit(denorm_min_val / -max_val));
   BOOST_CHECK(boost::math::signbit(-denorm_min_val / -max_val) == 0);
   BOOST_CHECK(boost::math::signbit(-denorm_min_val / max_val));
   BOOST_CHECK(boost::math::signbit(denorm_min_val / 2) == 0);
   BOOST_CHECK(boost::math::signbit(denorm_min_val / -2));
   BOOST_CHECK(boost::math::signbit(-denorm_min_val / -2) == 0);
   BOOST_CHECK(boost::math::signbit(-denorm_min_val / 2));

   test_type neg_denorm_zero = denorm_min_val * -denorm_min_val;

   BOOST_CHECK_EQUAL(neg_zero, neg_denorm_zero);

   test_type zero     = 0;
   // Arithmetic involving signed zero:
   BOOST_CHECK_EQUAL(-neg_zero, 0);
   BOOST_CHECK(!boost::math::signbit(-neg_zero));
   BOOST_CHECK_EQUAL(neg_zero + 2, 2);
   BOOST_CHECK_EQUAL(neg_zero + test_type(2), 2);
   BOOST_CHECK_EQUAL(2 + neg_zero, 2);
   BOOST_CHECK_EQUAL(test_type(2) + neg_zero, 2);
   BOOST_CHECK_EQUAL(neg_zero + -2, -2);
   BOOST_CHECK_EQUAL(neg_zero + test_type(-2), -2);
   BOOST_CHECK_EQUAL(-2 + neg_zero, -2);
   BOOST_CHECK_EQUAL(test_type(-2) + neg_zero, -2);
   BOOST_CHECK_EQUAL(neg_zero - 2, -2);
   BOOST_CHECK_EQUAL(neg_zero - test_type(2), -2);
   BOOST_CHECK_EQUAL(2 - neg_zero, 2);
   BOOST_CHECK_EQUAL(test_type(2) - neg_zero, 2);
   BOOST_CHECK_EQUAL(neg_zero - -2, 2);
   BOOST_CHECK_EQUAL(neg_zero - test_type(-2), 2);
   BOOST_CHECK_EQUAL(-2 - neg_zero, -2);
   BOOST_CHECK_EQUAL(test_type(-2) - neg_zero, -2);
   BOOST_CHECK(!boost::math::signbit(test_type(2) + test_type(-2)));
   BOOST_CHECK(!boost::math::signbit(test_type(2) - test_type(2)));
   BOOST_CHECK(!boost::math::signbit(test_type(-2) - test_type(-2)));
   BOOST_CHECK(!boost::math::signbit(test_type(-2) + test_type(2)));
   BOOST_CHECK(!boost::math::signbit(zero + zero));
   BOOST_CHECK(!boost::math::signbit(zero - zero));
   BOOST_CHECK(!boost::math::signbit(neg_zero + zero));
   BOOST_CHECK(!boost::math::signbit(zero + neg_zero));
   BOOST_CHECK(boost::math::signbit(neg_zero + neg_zero));
   BOOST_CHECK(boost::math::signbit(neg_zero - zero));
   BOOST_CHECK(!boost::math::signbit(zero - neg_zero));
   BOOST_CHECK(!boost::math::signbit(neg_zero - neg_zero));
   small = 0.25;
   BOOST_CHECK(!boost::math::signbit(floor(small)));
   BOOST_CHECK(!boost::math::signbit(round(small)));
   BOOST_CHECK(!boost::math::signbit(trunc(small)));
   small = -small;
   BOOST_CHECK(boost::math::signbit(ceil(small)));
   BOOST_CHECK(boost::math::signbit(round(small)));
   BOOST_CHECK(boost::math::signbit(trunc(small)));

   BOOST_CHECK_EQUAL(neg_zero * 2, 0);
   BOOST_CHECK_EQUAL(neg_zero * test_type(2), 0);
   BOOST_CHECK_EQUAL(2 * neg_zero, 0);
   BOOST_CHECK_EQUAL(test_type(2) * neg_zero, 0);
   BOOST_CHECK_EQUAL(neg_zero * -2, 0);
   BOOST_CHECK_EQUAL(neg_zero * test_type(-2), 0);
   BOOST_CHECK_EQUAL(-2 * neg_zero, 0);
   BOOST_CHECK_EQUAL(test_type(-2) * neg_zero, 0);
   BOOST_CHECK(boost::math::signbit(neg_zero * 2));
   BOOST_CHECK(boost::math::signbit(neg_zero * test_type(2)));
   BOOST_CHECK(boost::math::signbit(2 * neg_zero));
   BOOST_CHECK(boost::math::signbit(test_type(2) * neg_zero));
   BOOST_CHECK(!boost::math::signbit(neg_zero * -2));
   BOOST_CHECK(!boost::math::signbit(neg_zero * test_type(-2)));
   BOOST_CHECK(!boost::math::signbit(-2 * neg_zero));
   BOOST_CHECK(!boost::math::signbit(test_type(-2) * neg_zero));

   BOOST_CHECK_EQUAL(neg_zero / 2, 0);
   BOOST_CHECK_EQUAL(neg_zero / test_type(2), 0);
   BOOST_CHECK_EQUAL(2 / neg_zero, -inf_val);
   BOOST_CHECK_EQUAL(test_type(2) / neg_zero, -inf_val);
   BOOST_CHECK_EQUAL(neg_zero / -2, 0);
   BOOST_CHECK_EQUAL(neg_zero / test_type(-2), 0);
   BOOST_CHECK_EQUAL(-2 / neg_zero, inf_val);
   BOOST_CHECK_EQUAL(test_type(-2) / neg_zero, inf_val);
   BOOST_CHECK(boost::math::signbit(neg_zero / 2));
   BOOST_CHECK(boost::math::signbit(neg_zero / test_type(2)));
   BOOST_CHECK(boost::math::signbit(2 / neg_zero));
   BOOST_CHECK(boost::math::signbit(test_type(2) / neg_zero));
   BOOST_CHECK(!boost::math::signbit(neg_zero / -2));
   BOOST_CHECK(!boost::math::signbit(neg_zero / test_type(-2)));
   BOOST_CHECK(!boost::math::signbit(-2 / neg_zero));
   BOOST_CHECK(!boost::math::signbit(test_type(-2) / neg_zero));

   BOOST_CHECK(boost::math::signbit(neg_zero.convert_to<double>()));
   BOOST_CHECK(boost::math::signbit(neg_zero.convert_to<float>()));
   BOOST_CHECK(boost::math::signbit(neg_zero.convert_to<long double>()));
   BOOST_CHECK(!boost::math::signbit(zero.convert_to<double>()));
   BOOST_CHECK(!boost::math::signbit(zero.convert_to<float>()));
   BOOST_CHECK(!boost::math::signbit(zero.convert_to<long double>()));

   // Conversions to other types of special values:
   if (std::numeric_limits<float>::has_infinity)
   {
      BOOST_CHECK_EQUAL(inf_val.convert_to<float>(), std::numeric_limits<float>::infinity());
      BOOST_CHECK_EQUAL((-inf_val).convert_to<float>(), -std::numeric_limits<float>::infinity());
   }
   if (std::numeric_limits<float>::has_quiet_NaN)
   {
      BOOST_CHECK((boost::math::isnan)(nan_val.convert_to<float>()));
   }
   if (std::numeric_limits<double>::has_infinity)
   {
      BOOST_CHECK_EQUAL(inf_val.convert_to<double>(), std::numeric_limits<double>::infinity());
      BOOST_CHECK_EQUAL((-inf_val).convert_to<double>(), -std::numeric_limits<double>::infinity());
   }
   if (std::numeric_limits<double>::has_quiet_NaN)
   {
      BOOST_CHECK((boost::math::isnan)(nan_val.convert_to<double>()));
   }
   if (std::numeric_limits<long double>::has_infinity)
   {
      BOOST_CHECK_EQUAL(inf_val.convert_to<long double>(), std::numeric_limits<long double>::infinity());
      BOOST_CHECK_EQUAL((-inf_val).convert_to<long double>(), -std::numeric_limits<long double>::infinity());
   }
   if (std::numeric_limits<long double>::has_quiet_NaN)
   {
      BOOST_CHECK((boost::math::isnan)(nan_val.convert_to<long double>()));
   }
   //
   // Bug https://svn.boost.org/trac/boost/attachment/ticket/12580
   //
   using std::ldexp;
   test_type a(1);
   test_type b = ldexp(test_type(0.99), -std::numeric_limits<test_type>::digits);
   good_type ga(1);
   good_type gb = ldexp(good_type(0.99), -std::numeric_limits<good_type>::digits);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   b  = ldexp(test_type(0.5), -std::numeric_limits<test_type>::digits);
   gb = ldexp(good_type(0.5), -std::numeric_limits<good_type>::digits);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   b  = ldexp(test_type(1), -std::numeric_limits<test_type>::digits);
   gb = ldexp(good_type(1), -std::numeric_limits<good_type>::digits);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   b  = ldexp(test_type(0.50000000001), -std::numeric_limits<test_type>::digits);
   gb = ldexp(good_type(0.50000000001), -std::numeric_limits<good_type>::digits);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   a  = a + ldexp(a, -20);
   ga = ga + ldexp(ga, -20);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   b  = ldexp(test_type(0.5), -std::numeric_limits<test_type>::digits);
   gb = ldexp(good_type(0.5), -std::numeric_limits<good_type>::digits);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   b  = ldexp(test_type(1), -std::numeric_limits<test_type>::digits);
   gb = ldexp(good_type(1), -std::numeric_limits<good_type>::digits);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   b  = ldexp(test_type(0.50000000001), -std::numeric_limits<test_type>::digits);
   gb = ldexp(good_type(0.50000000001), -std::numeric_limits<good_type>::digits);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   a  = 1;
   a  = boost::math::float_prior(a);
   ga = 1;
   ga = boost::math::float_prior(ga);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   b  = ldexp(test_type(0.5), -std::numeric_limits<test_type>::digits);
   gb = ldexp(good_type(0.5), -std::numeric_limits<good_type>::digits);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   b  = ldexp(test_type(1), -std::numeric_limits<test_type>::digits);
   gb = ldexp(good_type(1), -std::numeric_limits<good_type>::digits);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   b  = ldexp(test_type(0.50000000001), -std::numeric_limits<test_type>::digits);
   gb = ldexp(good_type(0.50000000001), -std::numeric_limits<good_type>::digits);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   a = boost::math::float_next(test_type(1));
   ga = boost::math::float_next(good_type(1));
   b  = ldexp(boost::math::float_prior(test_type(1)), -std::numeric_limits<test_type>::digits);
   gb = ldexp(boost::math::float_prior(good_type(1)), -std::numeric_limits<test_type>::digits);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   b = ldexp(b, -1);
   gb = ldexp(gb, -1);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   a = 1.75;  // even mantissa, not a power of 2
   ga = 1.75;
   b  = ldexp(test_type(1), -std::numeric_limits<test_type>::digits);
   gb = ldexp(good_type(1), -std::numeric_limits<test_type>::digits);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));
   b = ldexp(b, -1);
   gb = ldexp(gb, -1);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   b  = ldexp(boost::math::float_prior(test_type(1)), -std::numeric_limits<test_type>::digits);
   gb = ldexp(boost::math::float_prior(good_type(1)), -std::numeric_limits<test_type>::digits);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   b  = ldexp(b, -1);
   gb = ldexp(gb, -1);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   b  = ldexp(test_type(0.75), -std::numeric_limits<test_type>::digits);  // even mantissa not a power of 2.
   gb = ldexp(good_type(0.75), -std::numeric_limits<test_type>::digits);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));

   b  = ldexp(b, -1);
   gb = ldexp(gb, -1);
   BOOST_CHECK_EQUAL(good_type(test_type(a - b)), good_type(ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - a)), good_type(gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + b)), good_type(ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + a)), good_type(gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(a - -b)), good_type(ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b - -a)), good_type(gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(a + -b)), good_type(ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(b + -a)), good_type(gb + -ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - b)), good_type(-ga - gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - a)), good_type(-gb - ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + b)), good_type(-ga + gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + a)), good_type(-gb + ga));

   BOOST_CHECK_EQUAL(good_type(test_type(-a - -b)), good_type(-ga - -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b - -a)), good_type(-gb - -ga));
   BOOST_CHECK_EQUAL(good_type(test_type(-a + -b)), good_type(-ga + -gb));
   BOOST_CHECK_EQUAL(good_type(test_type(-b + -a)), good_type(-gb + -ga));
   #endif
}

int main()
{
   // compile times are too long for CI when ASAN is enabled, prune things down a bit:
#if !defined(BOOST_CI_ASAN_BUILD) && !defined(BOOST_CI_USAN_BUID)
   test_special_cases();
#endif
   unsigned error_count = 0;
   for (unsigned i = 0; i < 100000; ++i)
   {
      good_type a = generate_random<good_type>();
      good_type b = generate_random<good_type>();
      test_type ta(a);
      test_type tb(b);
      BOOST_CHECK_EQUAL(test_type(a * b), ta * tb);
      BOOST_CHECK_EQUAL(test_type(-a * b), -ta * tb);
      BOOST_CHECK_EQUAL(test_type(a * -b), ta * -tb);
      BOOST_CHECK_EQUAL(test_type(-a * -b), -ta * -tb);

      BOOST_CHECK_EQUAL(test_type(a + b), ta + tb);
      BOOST_CHECK_EQUAL(test_type(-a + b), -ta + tb);
      BOOST_CHECK_EQUAL(test_type(a + -b), ta + -tb);
      BOOST_CHECK_EQUAL(test_type(-a + -b), -ta + -tb);

      BOOST_CHECK_EQUAL(test_type(a - b), ta - tb);
      BOOST_CHECK_EQUAL(test_type(-a - b), -ta - tb);
      BOOST_CHECK_EQUAL(test_type(a - -b), ta - -tb);
      BOOST_CHECK_EQUAL(test_type(-a - -b), -ta - -tb);

      BOOST_CHECK_EQUAL(test_type(a / b), ta / tb);
      BOOST_CHECK_EQUAL(test_type(-a / b), -ta / tb);
      BOOST_CHECK_EQUAL(test_type(a / -b), ta / -tb);
      BOOST_CHECK_EQUAL(test_type(-a / -b), -ta / -tb);

      BOOST_CHECK_EQUAL(test_type(sqrt(a)), sqrt(ta));
      BOOST_CHECK_EQUAL(test_type(floor(a)), floor(ta));
      BOOST_CHECK_EQUAL(test_type(floor(-a)), floor(-ta));
      BOOST_CHECK_EQUAL(test_type(ceil(a)), ceil(ta));
      BOOST_CHECK_EQUAL(test_type(ceil(-a)), ceil(-ta));

#ifdef TEST_MPFR
      //
      // Conversions:
      //
      BOOST_CHECK_EQUAL(a.convert_to<double>(), ta.convert_to<double>());
      BOOST_CHECK_EQUAL(a.convert_to<float>(), ta.convert_to<float>());
      BOOST_CHECK_EQUAL(b.convert_to<double>(), tb.convert_to<double>());
      BOOST_CHECK_EQUAL(b.convert_to<float>(), tb.convert_to<float>());
#else
      BOOST_CHECK_EQUAL(a, ta.convert_to<double>());
      BOOST_CHECK_EQUAL(static_cast<float>(a), ta.convert_to<float>());
      BOOST_CHECK_EQUAL(b, tb.convert_to<double>());
      BOOST_CHECK_EQUAL(static_cast<float>(b), tb.convert_to<float>());
#endif

      static boost::random::mt19937 i_gen;

      int si = i_gen();
      BOOST_CHECK_EQUAL(test_type(a * si), ta * si);
      BOOST_CHECK_EQUAL(test_type(-a * si), -ta * si);
      BOOST_CHECK_EQUAL(test_type(-a * -si), -ta * -si);
      BOOST_CHECK_EQUAL(test_type(a * -si), ta * -si);
      unsigned ui = std::abs(si);
      BOOST_CHECK_EQUAL(test_type(a * ui), ta * ui);
      BOOST_CHECK_EQUAL(test_type(-a * ui), -ta * ui);

      // Divide:
      BOOST_CHECK_EQUAL(test_type(a / si), ta / si);
      BOOST_CHECK_EQUAL(test_type(-a / si), -ta / si);
      BOOST_CHECK_EQUAL(test_type(-a / -si), -ta / -si);
      BOOST_CHECK_EQUAL(test_type(a / -si), ta / -si);
      BOOST_CHECK_EQUAL(test_type(a / ui), ta / ui);
      BOOST_CHECK_EQUAL(test_type(-a / ui), -ta / ui);
      // Error reporting:
      if ((unsigned)boost::detail::test_errors() != error_count)
      {
         error_count = boost::detail::test_errors();
         std::cout << std::setprecision(std::numeric_limits<test_type>::max_digits10) << std::scientific;
         std::cout << "a (mpfr) = " << a << std::endl;
         std::cout << "a (test) = " << ta << std::endl;
         std::cout << "b (mpfr) = " << b << std::endl;
         std::cout << "b (test) = " << tb << std::endl;
         std::cout << "si       = " << si << std::endl;
         std::cout << "ui       = " << ui << std::endl;
      }
   }
   return boost::report_errors();
}