1 /*
2  * src/bits.cc
3  *
4  * This work was supported by the Director, Office of Science, Division
5  * of Mathematical, Information, and Computational Sciences of the
6  * U.S. Department of Energy under contract number DE-AC03-76SF00098.
7  *
8  * Copyright (c) 2000-2001
9  *
10  * Defines various routines to get / set bits of a IEEE floating point
11  * number.  This used by the library for debugging purposes.
12  */
13 
14 #include <iostream>
15 #include <iomanip>
16 #include <cmath>
17 #include <climits>
18 
19 #include "config.h"
20 #include <qd/inline.h>
21 #include <qd/bits.h>
22 
23 #ifdef HAVE_IEEEFP_H
24 #include <ieeefp.h>
25 #endif
26 
27 using std::setw;
28 
get_double_expn(double x)29 int get_double_expn(double x) {
30   if (x == 0.0)
31     return INT_MIN;
32   if (QD_ISINF(x) || QD_ISNAN(x))
33     return INT_MAX;
34 
35   double y = std::abs(x);
36   int i = 0;
37   if (y < 1.0) {
38     while (y < 1.0) {
39       y *= 2.0;
40       i++;
41     }
42     return -i;
43   } else if (y >= 2.0) {
44     while (y >= 2.0) {
45       y *= 0.5;
46       i++;
47     }
48     return i;
49   }
50   return 0;
51 }
52 
print_double_info(std::ostream & os,double x)53 void print_double_info(std::ostream &os, double x) {
54   std::streamsize old_prec = os.precision(19);
55   std::ios_base::fmtflags old_flags  = os.flags();
56   os << std::scientific;
57 
58   os << setw(27) << x << ' ';
59   if (QD_ISNAN(x) || QD_ISINF(x) || (x == 0.0)) {
60     os << "                                                           ";
61   } else {
62 
63     x = std::abs(x);
64     int expn = get_double_expn(x);
65     double d = std::ldexp(1.0, expn);
66     os << setw(5) << expn << " ";
67     for (int i = 0; i < 53; i++) {
68       if (x >= d) {
69         x -= d;
70         os << '1';
71       } else
72         os << '0';
73       d *= 0.5;
74     }
75 
76     if (x != 0.0) {
77       // should not happen
78       os << " +trailing stuff";
79     }
80   }
81 
82   os.precision(old_prec);
83   os.flags(old_flags);
84 }
85 
86