1 module gcc.fpmath;
2 
3 enum
4 {
5     FP_NAN = 1,
6     FP_INFINITE,
7     FP_ZERO,
8     FP_SUBNORMAL,
9     FP_NORMAL,
10 }
11 
12 enum RealFormat
13 {
14     SameAsDouble,
15     DoubleDouble,
16     Intel80,
17 }
18 
19 struct Info {
20     static if (real.sizeof == double.sizeof) {
21         static const RealFormat realFormat = RealFormat.SameAsDouble;
22     } else version (PPC) {
23         static const RealFormat realFormat = RealFormat.DoubleDouble;
24         union real_rec {
25             real f;
26             struct { double hd, ld; }
27         }
28     } else version (PPC64) {
29         static const RealFormat realFormat = RealFormat.DoubleDouble;
30         union real_rec {
31             real f;
32             struct { double hd, ld; }
33         }
34     } else version (X86) {
35         static const RealFormat realFormat = RealFormat.Intel80;
36         union real_rec {
37             real f;
38             struct { uint li, mi, hi; }
39         }
40     } else version (X86_64) {
41         static const RealFormat realFormat = RealFormat.Intel80;
42         union real_rec {
43             real f;
44             struct { uint li, mi, hi; }
45         }
46     } else {
47         static assert(0);
48     }
49 }
50 
51 union float_rec {
52     float f;
53     uint  i;
54 }
55 
56 int signbit(float f)
57 {
58     float_rec r = void;
59     r.f = f;
60     return r.i & 0x80000000;
61 }
62 
63 int fpclassify(float f)
64 {
65     float_rec r = void;
66     r.f = f;
67     uint i = r.i & 0x7fffffff;
68 
69     if (! i)
70         return FP_ZERO;
71     else if (i < 0x00800000)
72         return FP_SUBNORMAL;
73     else if (i < 0x7f800000)
74         return FP_NORMAL;
75     else if (i < 0x7f800001)
76         return FP_INFINITE;
77     else
78         return FP_NAN;
79 }
80 
81 union double_rec {
82     double f;
83     struct {
84         version (BigEndian)
85             uint  hi, li;
86         else
87             uint  li, hi;
88     }
89 }
90 
91 int signbit(double f)
92 {
93     double_rec r = void;
94     r.f = f;
95     return r.hi & 0x80000000;
96 }
97 
98 int fpclassify(double f)
99 {
100     double_rec r = void;
101     r.f = f;
102     uint i = r.hi & 0x7fffffff;
103 
104     if (! (i | r.li))
105         return FP_ZERO;
106     else if (i <  0x00100000)
107         return FP_SUBNORMAL;
108     else if (i <  0x7ff00000)
109         return FP_NORMAL;
110     else if (i == 0x7ff00000 && ! r.li)
111         return FP_INFINITE;
112     else
113         return FP_NAN;
114 }
115 
116 int signbit(real f)
117 {
118     static if (Info.realFormat == RealFormat.SameAsDouble) {
119         return signbit(cast(double) f);
120     } else static if (Info.realFormat == RealFormat.DoubleDouble) {
121         Info.real_rec r = void;
122         r.f = f;
123         return signbit(r.hd);
124     } else static if (Info.realFormat == RealFormat.Intel80) {
125         Info.real_rec r = void;
126         r.f = f;
127         return r.hi & 0x00008000;
128     }
129 }
130 
131 int fpclassify(real f)
132 {
133     static if (Info.realFormat == RealFormat.SameAsDouble) {
134         return fpclassify(cast(double) f);
135     } else static if (Info.realFormat == RealFormat.DoubleDouble) {
136         Info.real_rec r = void;
137         r.f = f;
138         return fpclassify(r.hd);
139     } else static if (Info.realFormat == RealFormat.Intel80) {
140         Info.real_rec r = void;
141         r.f = f;
142         uint i = r.hi & 0x00007fff;
143         uint li = r.li | (r.mi & 0x7fffffff) ;
144         if (! i && ! li)
145             return FP_ZERO;
146         else if (i <  0x00000001 && (r.mi & 0x80000000) == 0)
147             return FP_SUBNORMAL;
148         else if (i <  0x00007fff)
149             return FP_NORMAL;
150         else if (i == 0x00007fff && ! li)
151             return FP_INFINITE;
152         else
153             return FP_NAN;
154     }
155 }
156 
157 unittest
158 {
159     static if (Info.realFormat == RealFormat.SameAsDouble) {
160         const real xrsn = 0x1p-1050;
161     } else static if (Info.realFormat == RealFormat.DoubleDouble) {
162         const real xrsn = 0x1p-1050;
163     } else static if (Info.realFormat == RealFormat.Intel80) {
164         const real xrsn = 0x1p-16390;
165     }
166 
167     static float[]  xfi = [ float.nan, -float.nan, float.infinity, -float.infinity,
168         0.0f, -0.0f, 0x1p-135f, -0x1p-135f, 4.2f, -4.2f ];
169     static double[] xdi = [ double.nan, -double.nan, double.infinity, -double.infinity,
170         0.0, -0.0, 0x1p-1050, -0x1p-1050, 4.2, -4.2 ];
171     static real[]   xri = [ real.nan, -real.nan, real.infinity, -real.infinity,
172         0.0L, -0.0L, xrsn, -xrsn, 4.2L, -4.2L ];
173     static int[]     xo = [ FP_NAN, FP_NAN, FP_INFINITE, FP_INFINITE,
174         FP_ZERO, FP_ZERO, FP_SUBNORMAL, FP_SUBNORMAL, FP_NORMAL, FP_NORMAL];
175 
176     foreach (int i, int cls; xo) {
177         assert( fpclassify(xfi[i]) == xo[i] );
178         assert( fpclassify(xdi[i]) == xo[i] );
179         assert( fpclassify(xri[i]) == xo[i] );
180         assert( ( signbit(xfi[i]) ?1:0 ) == (i & 1) );
181         assert( ( signbit(xdi[i]) ?1:0 ) == (i & 1) );
182         assert( ( signbit(xri[i]) ?1:0 ) == (i & 1) );
183     }
184 }