xref: /aosp_15_r20/external/arm-optimized-routines/math/test/rtest/semi.c (revision 412f47f9e737e10ed5cc46ec6a8d7fa2264f8a14)
1*412f47f9SXin Li /*
2*412f47f9SXin Li  * semi.c: test implementations of mathlib seminumerical functions
3*412f47f9SXin Li  *
4*412f47f9SXin Li  * Copyright (c) 1999-2019, Arm Limited.
5*412f47f9SXin Li  * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6*412f47f9SXin Li  */
7*412f47f9SXin Li 
8*412f47f9SXin Li #include <stdio.h>
9*412f47f9SXin Li #include "semi.h"
10*412f47f9SXin Li 
test_rint(uint32 * in,uint32 * out,int isfloor,int isceil)11*412f47f9SXin Li static void test_rint(uint32 *in, uint32 *out,
12*412f47f9SXin Li                        int isfloor, int isceil) {
13*412f47f9SXin Li     int sign = in[0] & 0x80000000;
14*412f47f9SXin Li     int roundup = (isfloor && sign) || (isceil && !sign);
15*412f47f9SXin Li     uint32 xh, xl, roundword;
16*412f47f9SXin Li     int ex = (in[0] >> 20) & 0x7FF;    /* exponent */
17*412f47f9SXin Li     int i;
18*412f47f9SXin Li 
19*412f47f9SXin Li     if ((ex > 0x3ff + 52 - 1) ||     /* things this big can't be fractional */
20*412f47f9SXin Li         ((in[0] & 0x7FFFFFFF) == 0 && in[1] == 0)) {   /* zero */
21*412f47f9SXin Li         /* NaN, Inf, a large integer, or zero: just return the input */
22*412f47f9SXin Li         out[0] = in[0];
23*412f47f9SXin Li         out[1] = in[1];
24*412f47f9SXin Li         return;
25*412f47f9SXin Li     }
26*412f47f9SXin Li 
27*412f47f9SXin Li     /*
28*412f47f9SXin Li      * Special case: ex < 0x3ff, ie our number is in (0,1). Return
29*412f47f9SXin Li      * 1 or 0 according to roundup.
30*412f47f9SXin Li      */
31*412f47f9SXin Li     if (ex < 0x3ff) {
32*412f47f9SXin Li         out[0] = sign | (roundup ? 0x3FF00000 : 0);
33*412f47f9SXin Li         out[1] = 0;
34*412f47f9SXin Li         return;
35*412f47f9SXin Li     }
36*412f47f9SXin Li 
37*412f47f9SXin Li     /*
38*412f47f9SXin Li      * We're not short of time here, so we'll do this the hideously
39*412f47f9SXin Li      * inefficient way. Shift bit by bit so that the units place is
40*412f47f9SXin Li      * somewhere predictable, round, and shift back again.
41*412f47f9SXin Li      */
42*412f47f9SXin Li     xh = in[0];
43*412f47f9SXin Li     xl = in[1];
44*412f47f9SXin Li     roundword = 0;
45*412f47f9SXin Li     for (i = ex; i < 0x3ff + 52; i++) {
46*412f47f9SXin Li         if (roundword & 1)
47*412f47f9SXin Li             roundword |= 2;            /* preserve sticky bit */
48*412f47f9SXin Li         roundword = (roundword >> 1) | ((xl & 1) << 31);
49*412f47f9SXin Li         xl = (xl >> 1) | ((xh & 1) << 31);
50*412f47f9SXin Li         xh = xh >> 1;
51*412f47f9SXin Li     }
52*412f47f9SXin Li     if (roundword && roundup) {
53*412f47f9SXin Li         xl++;
54*412f47f9SXin Li         xh += (xl==0);
55*412f47f9SXin Li     }
56*412f47f9SXin Li     for (i = ex; i < 0x3ff + 52; i++) {
57*412f47f9SXin Li         xh = (xh << 1) | ((xl >> 31) & 1);
58*412f47f9SXin Li         xl = (xl & 0x7FFFFFFF) << 1;
59*412f47f9SXin Li     }
60*412f47f9SXin Li     out[0] = xh;
61*412f47f9SXin Li     out[1] = xl;
62*412f47f9SXin Li }
63*412f47f9SXin Li 
test_ceil(uint32 * in,uint32 * out)64*412f47f9SXin Li char *test_ceil(uint32 *in, uint32 *out) {
65*412f47f9SXin Li     test_rint(in, out, 0, 1);
66*412f47f9SXin Li     return NULL;
67*412f47f9SXin Li }
68*412f47f9SXin Li 
test_floor(uint32 * in,uint32 * out)69*412f47f9SXin Li char *test_floor(uint32 *in, uint32 *out) {
70*412f47f9SXin Li     test_rint(in, out, 1, 0);
71*412f47f9SXin Li     return NULL;
72*412f47f9SXin Li }
73*412f47f9SXin Li 
test_rintf(uint32 * in,uint32 * out,int isfloor,int isceil)74*412f47f9SXin Li static void test_rintf(uint32 *in, uint32 *out,
75*412f47f9SXin Li                        int isfloor, int isceil) {
76*412f47f9SXin Li     int sign = *in & 0x80000000;
77*412f47f9SXin Li     int roundup = (isfloor && sign) || (isceil && !sign);
78*412f47f9SXin Li     uint32 x, roundword;
79*412f47f9SXin Li     int ex = (*in >> 23) & 0xFF;       /* exponent */
80*412f47f9SXin Li     int i;
81*412f47f9SXin Li 
82*412f47f9SXin Li     if ((ex > 0x7f + 23 - 1) ||      /* things this big can't be fractional */
83*412f47f9SXin Li         (*in & 0x7FFFFFFF) == 0) {     /* zero */
84*412f47f9SXin Li         /* NaN, Inf, a large integer, or zero: just return the input */
85*412f47f9SXin Li         *out = *in;
86*412f47f9SXin Li         return;
87*412f47f9SXin Li     }
88*412f47f9SXin Li 
89*412f47f9SXin Li     /*
90*412f47f9SXin Li      * Special case: ex < 0x7f, ie our number is in (0,1). Return
91*412f47f9SXin Li      * 1 or 0 according to roundup.
92*412f47f9SXin Li      */
93*412f47f9SXin Li     if (ex < 0x7f) {
94*412f47f9SXin Li         *out = sign | (roundup ? 0x3F800000 : 0);
95*412f47f9SXin Li         return;
96*412f47f9SXin Li     }
97*412f47f9SXin Li 
98*412f47f9SXin Li     /*
99*412f47f9SXin Li      * We're not short of time here, so we'll do this the hideously
100*412f47f9SXin Li      * inefficient way. Shift bit by bit so that the units place is
101*412f47f9SXin Li      * somewhere predictable, round, and shift back again.
102*412f47f9SXin Li      */
103*412f47f9SXin Li     x = *in;
104*412f47f9SXin Li     roundword = 0;
105*412f47f9SXin Li     for (i = ex; i < 0x7F + 23; i++) {
106*412f47f9SXin Li         if (roundword & 1)
107*412f47f9SXin Li             roundword |= 2;            /* preserve sticky bit */
108*412f47f9SXin Li         roundword = (roundword >> 1) | ((x & 1) << 31);
109*412f47f9SXin Li         x = x >> 1;
110*412f47f9SXin Li     }
111*412f47f9SXin Li     if (roundword && roundup) {
112*412f47f9SXin Li         x++;
113*412f47f9SXin Li     }
114*412f47f9SXin Li     for (i = ex; i < 0x7F + 23; i++) {
115*412f47f9SXin Li         x = x << 1;
116*412f47f9SXin Li     }
117*412f47f9SXin Li     *out = x;
118*412f47f9SXin Li }
119*412f47f9SXin Li 
test_ceilf(uint32 * in,uint32 * out)120*412f47f9SXin Li char *test_ceilf(uint32 *in, uint32 *out) {
121*412f47f9SXin Li     test_rintf(in, out, 0, 1);
122*412f47f9SXin Li     return NULL;
123*412f47f9SXin Li }
124*412f47f9SXin Li 
test_floorf(uint32 * in,uint32 * out)125*412f47f9SXin Li char *test_floorf(uint32 *in, uint32 *out) {
126*412f47f9SXin Li     test_rintf(in, out, 1, 0);
127*412f47f9SXin Li     return NULL;
128*412f47f9SXin Li }
129*412f47f9SXin Li 
test_fmod(uint32 * a,uint32 * b,uint32 * out)130*412f47f9SXin Li char *test_fmod(uint32 *a, uint32 *b, uint32 *out) {
131*412f47f9SXin Li     int sign;
132*412f47f9SXin Li     int32 aex, bex;
133*412f47f9SXin Li     uint32 am[2], bm[2];
134*412f47f9SXin Li 
135*412f47f9SXin Li     if (((a[0] & 0x7FFFFFFF) << 1) + !!a[1] > 0xFFE00000 ||
136*412f47f9SXin Li         ((b[0] & 0x7FFFFFFF) << 1) + !!b[1] > 0xFFE00000) {
137*412f47f9SXin Li         /* a or b is NaN: return QNaN, optionally with IVO */
138*412f47f9SXin Li         uint32 an, bn;
139*412f47f9SXin Li         out[0] = 0x7ff80000;
140*412f47f9SXin Li         out[1] = 1;
141*412f47f9SXin Li         an = ((a[0] & 0x7FFFFFFF) << 1) + !!a[1];
142*412f47f9SXin Li         bn = ((b[0] & 0x7FFFFFFF) << 1) + !!b[1];
143*412f47f9SXin Li         if ((an > 0xFFE00000 && an < 0xFFF00000) ||
144*412f47f9SXin Li             (bn > 0xFFE00000 && bn < 0xFFF00000))
145*412f47f9SXin Li             return "i";                /* at least one SNaN: IVO */
146*412f47f9SXin Li         else
147*412f47f9SXin Li             return NULL;               /* no SNaNs, but at least 1 QNaN */
148*412f47f9SXin Li     }
149*412f47f9SXin Li     if ((b[0] & 0x7FFFFFFF) == 0 && b[1] == 0) {   /* b==0: EDOM */
150*412f47f9SXin Li         out[0] = 0x7ff80000;
151*412f47f9SXin Li         out[1] = 1;
152*412f47f9SXin Li         return "EDOM status=i";
153*412f47f9SXin Li     }
154*412f47f9SXin Li     if ((a[0] & 0x7FF00000) == 0x7FF00000) {   /* a==Inf: EDOM */
155*412f47f9SXin Li         out[0] = 0x7ff80000;
156*412f47f9SXin Li         out[1] = 1;
157*412f47f9SXin Li         return "EDOM status=i";
158*412f47f9SXin Li     }
159*412f47f9SXin Li     if ((b[0] & 0x7FF00000) == 0x7FF00000) {   /* b==Inf: return a */
160*412f47f9SXin Li         out[0] = a[0];
161*412f47f9SXin Li         out[1] = a[1];
162*412f47f9SXin Li         return NULL;
163*412f47f9SXin Li     }
164*412f47f9SXin Li     if ((a[0] & 0x7FFFFFFF) == 0 && a[1] == 0) {   /* a==0: return a */
165*412f47f9SXin Li         out[0] = a[0];
166*412f47f9SXin Li         out[1] = a[1];
167*412f47f9SXin Li         return NULL;
168*412f47f9SXin Li     }
169*412f47f9SXin Li 
170*412f47f9SXin Li     /*
171*412f47f9SXin Li      * OK. That's the special cases cleared out of the way. Now we
172*412f47f9SXin Li      * have finite (though not necessarily normal) a and b.
173*412f47f9SXin Li      */
174*412f47f9SXin Li     sign = a[0] & 0x80000000;          /* we discard sign of b */
175*412f47f9SXin Li     test_frexp(a, am, (uint32 *)&aex);
176*412f47f9SXin Li     test_frexp(b, bm, (uint32 *)&bex);
177*412f47f9SXin Li     am[0] &= 0xFFFFF, am[0] |= 0x100000;
178*412f47f9SXin Li     bm[0] &= 0xFFFFF, bm[0] |= 0x100000;
179*412f47f9SXin Li 
180*412f47f9SXin Li     while (aex >= bex) {
181*412f47f9SXin Li         if (am[0] > bm[0] || (am[0] == bm[0] && am[1] >= bm[1])) {
182*412f47f9SXin Li             am[1] -= bm[1];
183*412f47f9SXin Li             am[0] = am[0] - bm[0] - (am[1] > ~bm[1]);
184*412f47f9SXin Li         }
185*412f47f9SXin Li         if (aex > bex) {
186*412f47f9SXin Li             am[0] = (am[0] << 1) | ((am[1] & 0x80000000) >> 31);
187*412f47f9SXin Li             am[1] <<= 1;
188*412f47f9SXin Li             aex--;
189*412f47f9SXin Li         } else
190*412f47f9SXin Li             break;
191*412f47f9SXin Li     }
192*412f47f9SXin Li 
193*412f47f9SXin Li     /*
194*412f47f9SXin Li      * Renormalise final result; this can be cunningly done by
195*412f47f9SXin Li      * passing a denormal to ldexp.
196*412f47f9SXin Li      */
197*412f47f9SXin Li     aex += 0x3fd;
198*412f47f9SXin Li     am[0] |= sign;
199*412f47f9SXin Li     test_ldexp(am, (uint32 *)&aex, out);
200*412f47f9SXin Li 
201*412f47f9SXin Li     return NULL;                       /* FIXME */
202*412f47f9SXin Li }
203*412f47f9SXin Li 
test_fmodf(uint32 * a,uint32 * b,uint32 * out)204*412f47f9SXin Li char *test_fmodf(uint32 *a, uint32 *b, uint32 *out) {
205*412f47f9SXin Li     int sign;
206*412f47f9SXin Li     int32 aex, bex;
207*412f47f9SXin Li     uint32 am, bm;
208*412f47f9SXin Li 
209*412f47f9SXin Li     if ((*a & 0x7FFFFFFF) > 0x7F800000 ||
210*412f47f9SXin Li         (*b & 0x7FFFFFFF) > 0x7F800000) {
211*412f47f9SXin Li         /* a or b is NaN: return QNaN, optionally with IVO */
212*412f47f9SXin Li         uint32 an, bn;
213*412f47f9SXin Li         *out = 0x7fc00001;
214*412f47f9SXin Li         an = *a & 0x7FFFFFFF;
215*412f47f9SXin Li         bn = *b & 0x7FFFFFFF;
216*412f47f9SXin Li         if ((an > 0x7f800000 && an < 0x7fc00000) ||
217*412f47f9SXin Li             (bn > 0x7f800000 && bn < 0x7fc00000))
218*412f47f9SXin Li             return "i";                /* at least one SNaN: IVO */
219*412f47f9SXin Li         else
220*412f47f9SXin Li             return NULL;               /* no SNaNs, but at least 1 QNaN */
221*412f47f9SXin Li     }
222*412f47f9SXin Li     if ((*b & 0x7FFFFFFF) == 0) {      /* b==0: EDOM */
223*412f47f9SXin Li         *out = 0x7fc00001;
224*412f47f9SXin Li         return "EDOM status=i";
225*412f47f9SXin Li     }
226*412f47f9SXin Li     if ((*a & 0x7F800000) == 0x7F800000) {   /* a==Inf: EDOM */
227*412f47f9SXin Li         *out = 0x7fc00001;
228*412f47f9SXin Li         return "EDOM status=i";
229*412f47f9SXin Li     }
230*412f47f9SXin Li     if ((*b & 0x7F800000) == 0x7F800000) {   /* b==Inf: return a */
231*412f47f9SXin Li         *out = *a;
232*412f47f9SXin Li         return NULL;
233*412f47f9SXin Li     }
234*412f47f9SXin Li     if ((*a & 0x7FFFFFFF) == 0) {      /* a==0: return a */
235*412f47f9SXin Li         *out = *a;
236*412f47f9SXin Li         return NULL;
237*412f47f9SXin Li     }
238*412f47f9SXin Li 
239*412f47f9SXin Li     /*
240*412f47f9SXin Li      * OK. That's the special cases cleared out of the way. Now we
241*412f47f9SXin Li      * have finite (though not necessarily normal) a and b.
242*412f47f9SXin Li      */
243*412f47f9SXin Li     sign = a[0] & 0x80000000;          /* we discard sign of b */
244*412f47f9SXin Li     test_frexpf(a, &am, (uint32 *)&aex);
245*412f47f9SXin Li     test_frexpf(b, &bm, (uint32 *)&bex);
246*412f47f9SXin Li     am &= 0x7FFFFF, am |= 0x800000;
247*412f47f9SXin Li     bm &= 0x7FFFFF, bm |= 0x800000;
248*412f47f9SXin Li 
249*412f47f9SXin Li     while (aex >= bex) {
250*412f47f9SXin Li         if (am >= bm) {
251*412f47f9SXin Li             am -= bm;
252*412f47f9SXin Li         }
253*412f47f9SXin Li         if (aex > bex) {
254*412f47f9SXin Li             am <<= 1;
255*412f47f9SXin Li             aex--;
256*412f47f9SXin Li         } else
257*412f47f9SXin Li             break;
258*412f47f9SXin Li     }
259*412f47f9SXin Li 
260*412f47f9SXin Li     /*
261*412f47f9SXin Li      * Renormalise final result; this can be cunningly done by
262*412f47f9SXin Li      * passing a denormal to ldexp.
263*412f47f9SXin Li      */
264*412f47f9SXin Li     aex += 0x7d;
265*412f47f9SXin Li     am |= sign;
266*412f47f9SXin Li     test_ldexpf(&am, (uint32 *)&aex, out);
267*412f47f9SXin Li 
268*412f47f9SXin Li     return NULL;                       /* FIXME */
269*412f47f9SXin Li }
270*412f47f9SXin Li 
test_ldexp(uint32 * x,uint32 * np,uint32 * out)271*412f47f9SXin Li char *test_ldexp(uint32 *x, uint32 *np, uint32 *out) {
272*412f47f9SXin Li     int n = *np;
273*412f47f9SXin Li     int32 n2;
274*412f47f9SXin Li     uint32 y[2];
275*412f47f9SXin Li     int ex = (x[0] >> 20) & 0x7FF;     /* exponent */
276*412f47f9SXin Li     int sign = x[0] & 0x80000000;
277*412f47f9SXin Li 
278*412f47f9SXin Li     if (ex == 0x7FF) {                 /* inf/NaN; just return x */
279*412f47f9SXin Li         out[0] = x[0];
280*412f47f9SXin Li         out[1] = x[1];
281*412f47f9SXin Li         return NULL;
282*412f47f9SXin Li     }
283*412f47f9SXin Li     if ((x[0] & 0x7FFFFFFF) == 0 && x[1] == 0) {   /* zero: return x */
284*412f47f9SXin Li         out[0] = x[0];
285*412f47f9SXin Li         out[1] = x[1];
286*412f47f9SXin Li         return NULL;
287*412f47f9SXin Li     }
288*412f47f9SXin Li 
289*412f47f9SXin Li     test_frexp(x, y, (uint32 *)&n2);
290*412f47f9SXin Li     ex = n + n2;
291*412f47f9SXin Li     if (ex > 0x400) {                  /* overflow */
292*412f47f9SXin Li         out[0] = sign | 0x7FF00000;
293*412f47f9SXin Li         out[1] = 0;
294*412f47f9SXin Li         return "overflow";
295*412f47f9SXin Li     }
296*412f47f9SXin Li     /*
297*412f47f9SXin Li      * Underflow. 2^-1074 is 00000000.00000001; so if ex == -1074
298*412f47f9SXin Li      * then we have something [2^-1075,2^-1074). Under round-to-
299*412f47f9SXin Li      * nearest-even, this whole interval rounds up to 2^-1074,
300*412f47f9SXin Li      * except for the bottom endpoint which rounds to even and is
301*412f47f9SXin Li      * an underflow condition.
302*412f47f9SXin Li      *
303*412f47f9SXin Li      * So, ex < -1074 is definite underflow, and ex == -1074 is
304*412f47f9SXin Li      * underflow iff all mantissa bits are zero.
305*412f47f9SXin Li      */
306*412f47f9SXin Li     if (ex < -1074 || (ex == -1074 && (y[0] & 0xFFFFF) == 0 && y[1] == 0)) {
307*412f47f9SXin Li         out[0] = sign;                 /* underflow: correctly signed zero */
308*412f47f9SXin Li         out[1] = 0;
309*412f47f9SXin Li         return "underflow";
310*412f47f9SXin Li     }
311*412f47f9SXin Li 
312*412f47f9SXin Li     /*
313*412f47f9SXin Li      * No overflow or underflow; should be nice and simple, unless
314*412f47f9SXin Li      * we have to denormalise and round the result.
315*412f47f9SXin Li      */
316*412f47f9SXin Li     if (ex < -1021) {                  /* denormalise and round */
317*412f47f9SXin Li         uint32 roundword;
318*412f47f9SXin Li         y[0] &= 0x000FFFFF;
319*412f47f9SXin Li         y[0] |= 0x00100000;            /* set leading bit */
320*412f47f9SXin Li         roundword = 0;
321*412f47f9SXin Li         while (ex < -1021) {
322*412f47f9SXin Li             if (roundword & 1)
323*412f47f9SXin Li                 roundword |= 2;        /* preserve sticky bit */
324*412f47f9SXin Li             roundword = (roundword >> 1) | ((y[1] & 1) << 31);
325*412f47f9SXin Li             y[1] = (y[1] >> 1) | ((y[0] & 1) << 31);
326*412f47f9SXin Li             y[0] = y[0] >> 1;
327*412f47f9SXin Li             ex++;
328*412f47f9SXin Li         }
329*412f47f9SXin Li         if (roundword > 0x80000000 ||  /* round up */
330*412f47f9SXin Li             (roundword == 0x80000000 && (y[1] & 1))) {  /* round up to even */
331*412f47f9SXin Li             y[1]++;
332*412f47f9SXin Li             y[0] += (y[1] == 0);
333*412f47f9SXin Li         }
334*412f47f9SXin Li         out[0] = sign | y[0];
335*412f47f9SXin Li         out[1] = y[1];
336*412f47f9SXin Li         /* Proper ERANGE underflow was handled earlier, but we still
337*412f47f9SXin Li          * expect an IEEE Underflow exception if this partially
338*412f47f9SXin Li          * underflowed result is not exact. */
339*412f47f9SXin Li         if (roundword)
340*412f47f9SXin Li             return "u";
341*412f47f9SXin Li         return NULL;                   /* underflow was handled earlier */
342*412f47f9SXin Li     } else {
343*412f47f9SXin Li         out[0] = y[0] + (ex << 20);
344*412f47f9SXin Li         out[1] = y[1];
345*412f47f9SXin Li         return NULL;
346*412f47f9SXin Li     }
347*412f47f9SXin Li }
348*412f47f9SXin Li 
test_ldexpf(uint32 * x,uint32 * np,uint32 * out)349*412f47f9SXin Li char *test_ldexpf(uint32 *x, uint32 *np, uint32 *out) {
350*412f47f9SXin Li     int n = *np;
351*412f47f9SXin Li     int32 n2;
352*412f47f9SXin Li     uint32 y;
353*412f47f9SXin Li     int ex = (*x >> 23) & 0xFF;     /* exponent */
354*412f47f9SXin Li     int sign = *x & 0x80000000;
355*412f47f9SXin Li 
356*412f47f9SXin Li     if (ex == 0xFF) {                 /* inf/NaN; just return x */
357*412f47f9SXin Li         *out = *x;
358*412f47f9SXin Li         return NULL;
359*412f47f9SXin Li     }
360*412f47f9SXin Li     if ((*x & 0x7FFFFFFF) == 0) {      /* zero: return x */
361*412f47f9SXin Li         *out = *x;
362*412f47f9SXin Li         return NULL;
363*412f47f9SXin Li     }
364*412f47f9SXin Li 
365*412f47f9SXin Li     test_frexpf(x, &y, (uint32 *)&n2);
366*412f47f9SXin Li     ex = n + n2;
367*412f47f9SXin Li     if (ex > 0x80) {                  /* overflow */
368*412f47f9SXin Li         *out = sign | 0x7F800000;
369*412f47f9SXin Li         return "overflow";
370*412f47f9SXin Li     }
371*412f47f9SXin Li     /*
372*412f47f9SXin Li      * Underflow. 2^-149 is 00000001; so if ex == -149 then we have
373*412f47f9SXin Li      * something [2^-150,2^-149). Under round-to- nearest-even,
374*412f47f9SXin Li      * this whole interval rounds up to 2^-149, except for the
375*412f47f9SXin Li      * bottom endpoint which rounds to even and is an underflow
376*412f47f9SXin Li      * condition.
377*412f47f9SXin Li      *
378*412f47f9SXin Li      * So, ex < -149 is definite underflow, and ex == -149 is
379*412f47f9SXin Li      * underflow iff all mantissa bits are zero.
380*412f47f9SXin Li      */
381*412f47f9SXin Li     if (ex < -149 || (ex == -149 && (y & 0x7FFFFF) == 0)) {
382*412f47f9SXin Li         *out = sign;                 /* underflow: correctly signed zero */
383*412f47f9SXin Li         return "underflow";
384*412f47f9SXin Li     }
385*412f47f9SXin Li 
386*412f47f9SXin Li     /*
387*412f47f9SXin Li      * No overflow or underflow; should be nice and simple, unless
388*412f47f9SXin Li      * we have to denormalise and round the result.
389*412f47f9SXin Li      */
390*412f47f9SXin Li     if (ex < -125) {                  /* denormalise and round */
391*412f47f9SXin Li         uint32 roundword;
392*412f47f9SXin Li         y &= 0x007FFFFF;
393*412f47f9SXin Li         y |= 0x00800000;               /* set leading bit */
394*412f47f9SXin Li         roundword = 0;
395*412f47f9SXin Li         while (ex < -125) {
396*412f47f9SXin Li             if (roundword & 1)
397*412f47f9SXin Li                 roundword |= 2;        /* preserve sticky bit */
398*412f47f9SXin Li             roundword = (roundword >> 1) | ((y & 1) << 31);
399*412f47f9SXin Li             y = y >> 1;
400*412f47f9SXin Li             ex++;
401*412f47f9SXin Li         }
402*412f47f9SXin Li         if (roundword > 0x80000000 ||  /* round up */
403*412f47f9SXin Li             (roundword == 0x80000000 && (y & 1))) {  /* round up to even */
404*412f47f9SXin Li             y++;
405*412f47f9SXin Li         }
406*412f47f9SXin Li         *out = sign | y;
407*412f47f9SXin Li         /* Proper ERANGE underflow was handled earlier, but we still
408*412f47f9SXin Li          * expect an IEEE Underflow exception if this partially
409*412f47f9SXin Li          * underflowed result is not exact. */
410*412f47f9SXin Li         if (roundword)
411*412f47f9SXin Li             return "u";
412*412f47f9SXin Li         return NULL;                   /* underflow was handled earlier */
413*412f47f9SXin Li     } else {
414*412f47f9SXin Li         *out = y + (ex << 23);
415*412f47f9SXin Li         return NULL;
416*412f47f9SXin Li     }
417*412f47f9SXin Li }
418*412f47f9SXin Li 
test_frexp(uint32 * x,uint32 * out,uint32 * nout)419*412f47f9SXin Li char *test_frexp(uint32 *x, uint32 *out, uint32 *nout) {
420*412f47f9SXin Li     int ex = (x[0] >> 20) & 0x7FF;     /* exponent */
421*412f47f9SXin Li     if (ex == 0x7FF) {                 /* inf/NaN; return x/0 */
422*412f47f9SXin Li         out[0] = x[0];
423*412f47f9SXin Li         out[1] = x[1];
424*412f47f9SXin Li         nout[0] = 0;
425*412f47f9SXin Li         return NULL;
426*412f47f9SXin Li     }
427*412f47f9SXin Li     if (ex == 0) {                     /* denormals/zeros */
428*412f47f9SXin Li         int sign;
429*412f47f9SXin Li         uint32 xh, xl;
430*412f47f9SXin Li         if ((x[0] & 0x7FFFFFFF) == 0 && x[1] == 0) {
431*412f47f9SXin Li             /* zero: return x/0 */
432*412f47f9SXin Li             out[0] = x[0];
433*412f47f9SXin Li             out[1] = x[1];
434*412f47f9SXin Li             nout[0] = 0;
435*412f47f9SXin Li             return NULL;
436*412f47f9SXin Li         }
437*412f47f9SXin Li         sign = x[0] & 0x80000000;
438*412f47f9SXin Li         xh = x[0] & 0x7FFFFFFF;
439*412f47f9SXin Li         xl = x[1];
440*412f47f9SXin Li         ex = 1;
441*412f47f9SXin Li         while (!(xh & 0x100000)) {
442*412f47f9SXin Li             ex--;
443*412f47f9SXin Li             xh = (xh << 1) | ((xl >> 31) & 1);
444*412f47f9SXin Li             xl = (xl & 0x7FFFFFFF) << 1;
445*412f47f9SXin Li         }
446*412f47f9SXin Li         out[0] = sign | 0x3FE00000 | (xh & 0xFFFFF);
447*412f47f9SXin Li         out[1] = xl;
448*412f47f9SXin Li         nout[0] = ex - 0x3FE;
449*412f47f9SXin Li         return NULL;
450*412f47f9SXin Li     }
451*412f47f9SXin Li     out[0] = 0x3FE00000 | (x[0] & 0x800FFFFF);
452*412f47f9SXin Li     out[1] = x[1];
453*412f47f9SXin Li     nout[0] = ex - 0x3FE;
454*412f47f9SXin Li     return NULL;                       /* ordinary number; no error */
455*412f47f9SXin Li }
456*412f47f9SXin Li 
test_frexpf(uint32 * x,uint32 * out,uint32 * nout)457*412f47f9SXin Li char *test_frexpf(uint32 *x, uint32 *out, uint32 *nout) {
458*412f47f9SXin Li     int ex = (*x >> 23) & 0xFF;        /* exponent */
459*412f47f9SXin Li     if (ex == 0xFF) {                  /* inf/NaN; return x/0 */
460*412f47f9SXin Li         *out = *x;
461*412f47f9SXin Li         nout[0] = 0;
462*412f47f9SXin Li         return NULL;
463*412f47f9SXin Li     }
464*412f47f9SXin Li     if (ex == 0) {                     /* denormals/zeros */
465*412f47f9SXin Li         int sign;
466*412f47f9SXin Li         uint32 xv;
467*412f47f9SXin Li         if ((*x & 0x7FFFFFFF) == 0) {
468*412f47f9SXin Li             /* zero: return x/0 */
469*412f47f9SXin Li             *out = *x;
470*412f47f9SXin Li             nout[0] = 0;
471*412f47f9SXin Li             return NULL;
472*412f47f9SXin Li         }
473*412f47f9SXin Li         sign = *x & 0x80000000;
474*412f47f9SXin Li         xv = *x & 0x7FFFFFFF;
475*412f47f9SXin Li         ex = 1;
476*412f47f9SXin Li         while (!(xv & 0x800000)) {
477*412f47f9SXin Li             ex--;
478*412f47f9SXin Li             xv = xv << 1;
479*412f47f9SXin Li         }
480*412f47f9SXin Li         *out = sign | 0x3F000000 | (xv & 0x7FFFFF);
481*412f47f9SXin Li         nout[0] = ex - 0x7E;
482*412f47f9SXin Li         return NULL;
483*412f47f9SXin Li     }
484*412f47f9SXin Li     *out = 0x3F000000 | (*x & 0x807FFFFF);
485*412f47f9SXin Li     nout[0] = ex - 0x7E;
486*412f47f9SXin Li     return NULL;                       /* ordinary number; no error */
487*412f47f9SXin Li }
488*412f47f9SXin Li 
test_modf(uint32 * x,uint32 * fout,uint32 * iout)489*412f47f9SXin Li char *test_modf(uint32 *x, uint32 *fout, uint32 *iout) {
490*412f47f9SXin Li     int ex = (x[0] >> 20) & 0x7FF;     /* exponent */
491*412f47f9SXin Li     int sign = x[0] & 0x80000000;
492*412f47f9SXin Li     uint32 fh, fl;
493*412f47f9SXin Li 
494*412f47f9SXin Li     if (((x[0] & 0x7FFFFFFF) | (!!x[1])) > 0x7FF00000) {
495*412f47f9SXin Li         /*
496*412f47f9SXin Li          * NaN input: return the same in _both_ outputs.
497*412f47f9SXin Li          */
498*412f47f9SXin Li         fout[0] = iout[0] = x[0];
499*412f47f9SXin Li         fout[1] = iout[1] = x[1];
500*412f47f9SXin Li         return NULL;
501*412f47f9SXin Li     }
502*412f47f9SXin Li 
503*412f47f9SXin Li     test_rint(x, iout, 0, 0);
504*412f47f9SXin Li     fh = x[0] - iout[0];
505*412f47f9SXin Li     fl = x[1] - iout[1];
506*412f47f9SXin Li     if (!fh && !fl) {                  /* no fraction part */
507*412f47f9SXin Li         fout[0] = sign;
508*412f47f9SXin Li         fout[1] = 0;
509*412f47f9SXin Li         return NULL;
510*412f47f9SXin Li     }
511*412f47f9SXin Li     if (!(iout[0] & 0x7FFFFFFF) && !iout[1]) {   /* no integer part */
512*412f47f9SXin Li         fout[0] = x[0];
513*412f47f9SXin Li         fout[1] = x[1];
514*412f47f9SXin Li         return NULL;
515*412f47f9SXin Li     }
516*412f47f9SXin Li     while (!(fh & 0x100000)) {
517*412f47f9SXin Li         ex--;
518*412f47f9SXin Li         fh = (fh << 1) | ((fl >> 31) & 1);
519*412f47f9SXin Li         fl = (fl & 0x7FFFFFFF) << 1;
520*412f47f9SXin Li     }
521*412f47f9SXin Li     fout[0] = sign | (ex << 20) | (fh & 0xFFFFF);
522*412f47f9SXin Li     fout[1] = fl;
523*412f47f9SXin Li     return NULL;
524*412f47f9SXin Li }
525*412f47f9SXin Li 
test_modff(uint32 * x,uint32 * fout,uint32 * iout)526*412f47f9SXin Li char *test_modff(uint32 *x, uint32 *fout, uint32 *iout) {
527*412f47f9SXin Li     int ex = (*x >> 23) & 0xFF;        /* exponent */
528*412f47f9SXin Li     int sign = *x & 0x80000000;
529*412f47f9SXin Li     uint32 f;
530*412f47f9SXin Li 
531*412f47f9SXin Li     if ((*x & 0x7FFFFFFF) > 0x7F800000) {
532*412f47f9SXin Li         /*
533*412f47f9SXin Li          * NaN input: return the same in _both_ outputs.
534*412f47f9SXin Li          */
535*412f47f9SXin Li         *fout = *iout = *x;
536*412f47f9SXin Li         return NULL;
537*412f47f9SXin Li     }
538*412f47f9SXin Li 
539*412f47f9SXin Li     test_rintf(x, iout, 0, 0);
540*412f47f9SXin Li     f = *x - *iout;
541*412f47f9SXin Li     if (!f) {                          /* no fraction part */
542*412f47f9SXin Li         *fout = sign;
543*412f47f9SXin Li         return NULL;
544*412f47f9SXin Li     }
545*412f47f9SXin Li     if (!(*iout & 0x7FFFFFFF)) {       /* no integer part */
546*412f47f9SXin Li         *fout = *x;
547*412f47f9SXin Li         return NULL;
548*412f47f9SXin Li     }
549*412f47f9SXin Li     while (!(f & 0x800000)) {
550*412f47f9SXin Li         ex--;
551*412f47f9SXin Li         f = f << 1;
552*412f47f9SXin Li     }
553*412f47f9SXin Li     *fout = sign | (ex << 23) | (f & 0x7FFFFF);
554*412f47f9SXin Li     return NULL;
555*412f47f9SXin Li }
556*412f47f9SXin Li 
test_copysign(uint32 * x,uint32 * y,uint32 * out)557*412f47f9SXin Li char *test_copysign(uint32 *x, uint32 *y, uint32 *out)
558*412f47f9SXin Li {
559*412f47f9SXin Li     int ysign = y[0] & 0x80000000;
560*412f47f9SXin Li     int xhigh = x[0] & 0x7fffffff;
561*412f47f9SXin Li 
562*412f47f9SXin Li     out[0] = ysign | xhigh;
563*412f47f9SXin Li     out[1] = x[1];
564*412f47f9SXin Li 
565*412f47f9SXin Li     /* There can be no error */
566*412f47f9SXin Li     return NULL;
567*412f47f9SXin Li }
568*412f47f9SXin Li 
test_copysignf(uint32 * x,uint32 * y,uint32 * out)569*412f47f9SXin Li char *test_copysignf(uint32 *x, uint32 *y, uint32 *out)
570*412f47f9SXin Li {
571*412f47f9SXin Li     int ysign = y[0] & 0x80000000;
572*412f47f9SXin Li     int xhigh = x[0] & 0x7fffffff;
573*412f47f9SXin Li 
574*412f47f9SXin Li     out[0] = ysign | xhigh;
575*412f47f9SXin Li 
576*412f47f9SXin Li     /* There can be no error */
577*412f47f9SXin Li     return NULL;
578*412f47f9SXin Li }
579*412f47f9SXin Li 
test_isfinite(uint32 * x,uint32 * out)580*412f47f9SXin Li char *test_isfinite(uint32 *x, uint32 *out)
581*412f47f9SXin Li {
582*412f47f9SXin Li     int xhigh = x[0];
583*412f47f9SXin Li     /* Being finite means that the exponent is not 0x7ff */
584*412f47f9SXin Li     if ((xhigh & 0x7ff00000) == 0x7ff00000) out[0] = 0;
585*412f47f9SXin Li     else out[0] = 1;
586*412f47f9SXin Li     return NULL;
587*412f47f9SXin Li }
588*412f47f9SXin Li 
test_isfinitef(uint32 * x,uint32 * out)589*412f47f9SXin Li char *test_isfinitef(uint32 *x, uint32 *out)
590*412f47f9SXin Li {
591*412f47f9SXin Li     /* Being finite means that the exponent is not 0xff */
592*412f47f9SXin Li     if ((x[0] & 0x7f800000) == 0x7f800000) out[0] = 0;
593*412f47f9SXin Li     else out[0] = 1;
594*412f47f9SXin Li     return NULL;
595*412f47f9SXin Li }
596*412f47f9SXin Li 
test_isinff(uint32 * x,uint32 * out)597*412f47f9SXin Li char *test_isinff(uint32 *x, uint32 *out)
598*412f47f9SXin Li {
599*412f47f9SXin Li     /* Being infinite means that our bottom 30 bits equate to 0x7f800000 */
600*412f47f9SXin Li     if ((x[0] & 0x7fffffff) == 0x7f800000) out[0] = 1;
601*412f47f9SXin Li     else out[0] = 0;
602*412f47f9SXin Li     return NULL;
603*412f47f9SXin Li }
604*412f47f9SXin Li 
test_isinf(uint32 * x,uint32 * out)605*412f47f9SXin Li char *test_isinf(uint32 *x, uint32 *out)
606*412f47f9SXin Li {
607*412f47f9SXin Li     int xhigh = x[0];
608*412f47f9SXin Li     int xlow = x[1];
609*412f47f9SXin Li     /* Being infinite means that our fraction is zero and exponent is 0x7ff */
610*412f47f9SXin Li     if (((xhigh & 0x7fffffff) == 0x7ff00000) && (xlow == 0)) out[0] = 1;
611*412f47f9SXin Li     else out[0] = 0;
612*412f47f9SXin Li     return NULL;
613*412f47f9SXin Li }
614*412f47f9SXin Li 
test_isnanf(uint32 * x,uint32 * out)615*412f47f9SXin Li char *test_isnanf(uint32 *x, uint32 *out)
616*412f47f9SXin Li {
617*412f47f9SXin Li     /* Being NaN means that our exponent is 0xff and non-0 fraction */
618*412f47f9SXin Li     int exponent = x[0] & 0x7f800000;
619*412f47f9SXin Li     int fraction = x[0] & 0x007fffff;
620*412f47f9SXin Li     if ((exponent == 0x7f800000) && (fraction != 0)) out[0] = 1;
621*412f47f9SXin Li     else out[0] = 0;
622*412f47f9SXin Li     return NULL;
623*412f47f9SXin Li }
624*412f47f9SXin Li 
test_isnan(uint32 * x,uint32 * out)625*412f47f9SXin Li char *test_isnan(uint32 *x, uint32 *out)
626*412f47f9SXin Li {
627*412f47f9SXin Li     /* Being NaN means that our exponent is 0x7ff and non-0 fraction */
628*412f47f9SXin Li     int exponent = x[0] & 0x7ff00000;
629*412f47f9SXin Li     int fractionhigh = x[0] & 0x000fffff;
630*412f47f9SXin Li     if ((exponent == 0x7ff00000) && ((fractionhigh != 0) || x[1] != 0))
631*412f47f9SXin Li         out[0] = 1;
632*412f47f9SXin Li     else out[0] = 0;
633*412f47f9SXin Li     return NULL;
634*412f47f9SXin Li }
635*412f47f9SXin Li 
test_isnormalf(uint32 * x,uint32 * out)636*412f47f9SXin Li char *test_isnormalf(uint32 *x, uint32 *out)
637*412f47f9SXin Li {
638*412f47f9SXin Li     /* Being normal means exponent is not 0 and is not 0xff */
639*412f47f9SXin Li     int exponent = x[0] & 0x7f800000;
640*412f47f9SXin Li     if (exponent == 0x7f800000) out[0] = 0;
641*412f47f9SXin Li     else if (exponent == 0) out[0] = 0;
642*412f47f9SXin Li     else out[0] = 1;
643*412f47f9SXin Li     return NULL;
644*412f47f9SXin Li }
645*412f47f9SXin Li 
test_isnormal(uint32 * x,uint32 * out)646*412f47f9SXin Li char *test_isnormal(uint32 *x, uint32 *out)
647*412f47f9SXin Li {
648*412f47f9SXin Li     /* Being normal means exponent is not 0 and is not 0x7ff */
649*412f47f9SXin Li     int exponent = x[0] & 0x7ff00000;
650*412f47f9SXin Li     if (exponent == 0x7ff00000) out[0] = 0;
651*412f47f9SXin Li     else if (exponent == 0) out[0] = 0;
652*412f47f9SXin Li     else out[0] = 1;
653*412f47f9SXin Li     return NULL;
654*412f47f9SXin Li }
655*412f47f9SXin Li 
test_signbitf(uint32 * x,uint32 * out)656*412f47f9SXin Li char *test_signbitf(uint32 *x, uint32 *out)
657*412f47f9SXin Li {
658*412f47f9SXin Li     /* Sign bit is bit 31 */
659*412f47f9SXin Li     out[0] = (x[0] >> 31) & 1;
660*412f47f9SXin Li     return NULL;
661*412f47f9SXin Li }
662*412f47f9SXin Li 
test_signbit(uint32 * x,uint32 * out)663*412f47f9SXin Li char *test_signbit(uint32 *x, uint32 *out)
664*412f47f9SXin Li {
665*412f47f9SXin Li     /* Sign bit is bit 31 */
666*412f47f9SXin Li     out[0] = (x[0] >> 31) & 1;
667*412f47f9SXin Li     return NULL;
668*412f47f9SXin Li }
669*412f47f9SXin Li 
test_fpclassify(uint32 * x,uint32 * out)670*412f47f9SXin Li char *test_fpclassify(uint32 *x, uint32 *out)
671*412f47f9SXin Li {
672*412f47f9SXin Li     int exponent = (x[0] & 0x7ff00000) >> 20;
673*412f47f9SXin Li     int fraction = (x[0] & 0x000fffff) | x[1];
674*412f47f9SXin Li 
675*412f47f9SXin Li     if ((exponent == 0x00) && (fraction == 0)) out[0] = 0;
676*412f47f9SXin Li     else if ((exponent == 0x00) && (fraction != 0)) out[0] = 4;
677*412f47f9SXin Li     else if ((exponent == 0x7ff) && (fraction == 0)) out[0] = 3;
678*412f47f9SXin Li     else if ((exponent == 0x7ff) && (fraction != 0)) out[0] = 7;
679*412f47f9SXin Li     else out[0] = 5;
680*412f47f9SXin Li     return NULL;
681*412f47f9SXin Li }
682*412f47f9SXin Li 
test_fpclassifyf(uint32 * x,uint32 * out)683*412f47f9SXin Li char *test_fpclassifyf(uint32 *x, uint32 *out)
684*412f47f9SXin Li {
685*412f47f9SXin Li     int exponent = (x[0] & 0x7f800000) >> 23;
686*412f47f9SXin Li     int fraction = x[0] & 0x007fffff;
687*412f47f9SXin Li 
688*412f47f9SXin Li     if ((exponent == 0x000) && (fraction == 0)) out[0] = 0;
689*412f47f9SXin Li     else if ((exponent == 0x000) && (fraction != 0)) out[0] = 4;
690*412f47f9SXin Li     else if ((exponent == 0xff) && (fraction == 0)) out[0] = 3;
691*412f47f9SXin Li     else if ((exponent == 0xff) && (fraction != 0)) out[0] = 7;
692*412f47f9SXin Li     else out[0] = 5;
693*412f47f9SXin Li     return NULL;
694*412f47f9SXin Li }
695*412f47f9SXin Li 
696*412f47f9SXin Li /*
697*412f47f9SXin Li  * Internal function that compares doubles in x & y and returns -3, -2, -1, 0,
698*412f47f9SXin Li  * 1 if they compare to be signaling, unordered, less than, equal or greater
699*412f47f9SXin Li  * than.
700*412f47f9SXin Li  */
fpcmp4(uint32 * x,uint32 * y)701*412f47f9SXin Li static int fpcmp4(uint32 *x, uint32 *y)
702*412f47f9SXin Li {
703*412f47f9SXin Li     int result = 0;
704*412f47f9SXin Li 
705*412f47f9SXin Li     /*
706*412f47f9SXin Li      * Sort out whether results are ordered or not to begin with
707*412f47f9SXin Li      * NaNs have exponent 0x7ff, and non-zero fraction. Signaling NaNs take
708*412f47f9SXin Li      * higher priority than quiet ones.
709*412f47f9SXin Li      */
710*412f47f9SXin Li     if ((x[0] & 0x7fffffff) >= 0x7ff80000) result = -2;
711*412f47f9SXin Li     else if ((x[0] & 0x7fffffff) > 0x7ff00000) result = -3;
712*412f47f9SXin Li     else if (((x[0] & 0x7fffffff) == 0x7ff00000) && (x[1] != 0)) result = -3;
713*412f47f9SXin Li     if ((y[0] & 0x7fffffff) >= 0x7ff80000 && result != -3) result = -2;
714*412f47f9SXin Li     else if ((y[0] & 0x7fffffff) > 0x7ff00000) result = -3;
715*412f47f9SXin Li     else if (((y[0] & 0x7fffffff) == 0x7ff00000) && (y[1] != 0)) result = -3;
716*412f47f9SXin Li     if (result != 0) return result;
717*412f47f9SXin Li 
718*412f47f9SXin Li     /*
719*412f47f9SXin Li      * The two forms of zero are equal
720*412f47f9SXin Li      */
721*412f47f9SXin Li     if (((x[0] & 0x7fffffff) == 0) && x[1] == 0 &&
722*412f47f9SXin Li         ((y[0] & 0x7fffffff) == 0) && y[1] == 0)
723*412f47f9SXin Li         return 0;
724*412f47f9SXin Li 
725*412f47f9SXin Li     /*
726*412f47f9SXin Li      * If x and y have different signs we can tell that they're not equal
727*412f47f9SXin Li      * If x is +ve we have x > y return 1 - otherwise y is +ve return -1
728*412f47f9SXin Li      */
729*412f47f9SXin Li     if ((x[0] >> 31) != (y[0] >> 31))
730*412f47f9SXin Li         return ((x[0] >> 31) == 0) - ((y[0] >> 31) == 0);
731*412f47f9SXin Li 
732*412f47f9SXin Li     /*
733*412f47f9SXin Li      * Now we have both signs the same, let's do an initial compare of the
734*412f47f9SXin Li      * values.
735*412f47f9SXin Li      *
736*412f47f9SXin Li      * Whoever designed IEEE754's floating point formats is very clever and
737*412f47f9SXin Li      * earns my undying admiration.  Once you remove the sign-bit, the
738*412f47f9SXin Li      * floating point numbers can be ordered using the standard <, ==, >
739*412f47f9SXin Li      * operators will treating the fp-numbers as integers with that bit-
740*412f47f9SXin Li      * pattern.
741*412f47f9SXin Li      */
742*412f47f9SXin Li     if ((x[0] & 0x7fffffff) < (y[0] & 0x7fffffff)) result = -1;
743*412f47f9SXin Li     else if ((x[0] & 0x7fffffff) > (y[0] & 0x7fffffff)) result = 1;
744*412f47f9SXin Li     else if (x[1] < y[1]) result = -1;
745*412f47f9SXin Li     else if (x[1] > y[1]) result = 1;
746*412f47f9SXin Li     else result = 0;
747*412f47f9SXin Li 
748*412f47f9SXin Li     /*
749*412f47f9SXin Li      * Now we return the result - is x is positive (and therefore so is y) we
750*412f47f9SXin Li      * return the plain result - otherwise we negate it and return.
751*412f47f9SXin Li      */
752*412f47f9SXin Li     if ((x[0] >> 31) == 0) return result;
753*412f47f9SXin Li     else return -result;
754*412f47f9SXin Li }
755*412f47f9SXin Li 
756*412f47f9SXin Li /*
757*412f47f9SXin Li  * Internal function that compares floats in x & y and returns -3, -2, -1, 0,
758*412f47f9SXin Li  * 1 if they compare to be signaling, unordered, less than, equal or greater
759*412f47f9SXin Li  * than.
760*412f47f9SXin Li  */
fpcmp4f(uint32 * x,uint32 * y)761*412f47f9SXin Li static int fpcmp4f(uint32 *x, uint32 *y)
762*412f47f9SXin Li {
763*412f47f9SXin Li     int result = 0;
764*412f47f9SXin Li 
765*412f47f9SXin Li     /*
766*412f47f9SXin Li      * Sort out whether results are ordered or not to begin with
767*412f47f9SXin Li      * NaNs have exponent 0xff, and non-zero fraction - we have to handle all
768*412f47f9SXin Li      * signaling cases over the quiet ones
769*412f47f9SXin Li      */
770*412f47f9SXin Li     if ((x[0] & 0x7fffffff) >= 0x7fc00000) result = -2;
771*412f47f9SXin Li     else if ((x[0] & 0x7fffffff) > 0x7f800000) result = -3;
772*412f47f9SXin Li     if ((y[0] & 0x7fffffff) >= 0x7fc00000 && result != -3) result = -2;
773*412f47f9SXin Li     else if ((y[0] & 0x7fffffff) > 0x7f800000) result = -3;
774*412f47f9SXin Li     if (result != 0) return result;
775*412f47f9SXin Li 
776*412f47f9SXin Li     /*
777*412f47f9SXin Li      * The two forms of zero are equal
778*412f47f9SXin Li      */
779*412f47f9SXin Li     if (((x[0] & 0x7fffffff) == 0) && ((y[0] & 0x7fffffff) == 0))
780*412f47f9SXin Li         return 0;
781*412f47f9SXin Li 
782*412f47f9SXin Li     /*
783*412f47f9SXin Li      * If x and y have different signs we can tell that they're not equal
784*412f47f9SXin Li      * If x is +ve we have x > y return 1 - otherwise y is +ve return -1
785*412f47f9SXin Li      */
786*412f47f9SXin Li     if ((x[0] >> 31) != (y[0] >> 31))
787*412f47f9SXin Li         return ((x[0] >> 31) == 0) - ((y[0] >> 31) == 0);
788*412f47f9SXin Li 
789*412f47f9SXin Li     /*
790*412f47f9SXin Li      * Now we have both signs the same, let's do an initial compare of the
791*412f47f9SXin Li      * values.
792*412f47f9SXin Li      *
793*412f47f9SXin Li      * Whoever designed IEEE754's floating point formats is very clever and
794*412f47f9SXin Li      * earns my undying admiration.  Once you remove the sign-bit, the
795*412f47f9SXin Li      * floating point numbers can be ordered using the standard <, ==, >
796*412f47f9SXin Li      * operators will treating the fp-numbers as integers with that bit-
797*412f47f9SXin Li      * pattern.
798*412f47f9SXin Li      */
799*412f47f9SXin Li     if ((x[0] & 0x7fffffff) < (y[0] & 0x7fffffff)) result = -1;
800*412f47f9SXin Li     else if ((x[0] & 0x7fffffff) > (y[0] & 0x7fffffff)) result = 1;
801*412f47f9SXin Li     else result = 0;
802*412f47f9SXin Li 
803*412f47f9SXin Li     /*
804*412f47f9SXin Li      * Now we return the result - is x is positive (and therefore so is y) we
805*412f47f9SXin Li      * return the plain result - otherwise we negate it and return.
806*412f47f9SXin Li      */
807*412f47f9SXin Li     if ((x[0] >> 31) == 0) return result;
808*412f47f9SXin Li     else return -result;
809*412f47f9SXin Li }
810*412f47f9SXin Li 
test_isgreater(uint32 * x,uint32 * y,uint32 * out)811*412f47f9SXin Li char *test_isgreater(uint32 *x, uint32 *y, uint32 *out)
812*412f47f9SXin Li {
813*412f47f9SXin Li     int result = fpcmp4(x, y);
814*412f47f9SXin Li     *out = (result == 1);
815*412f47f9SXin Li     return result == -3 ? "i" : NULL;
816*412f47f9SXin Li }
817*412f47f9SXin Li 
test_isgreaterequal(uint32 * x,uint32 * y,uint32 * out)818*412f47f9SXin Li char *test_isgreaterequal(uint32 *x, uint32 *y, uint32 *out)
819*412f47f9SXin Li {
820*412f47f9SXin Li     int result = fpcmp4(x, y);
821*412f47f9SXin Li     *out = (result >= 0);
822*412f47f9SXin Li     return result == -3 ? "i" : NULL;
823*412f47f9SXin Li }
824*412f47f9SXin Li 
test_isless(uint32 * x,uint32 * y,uint32 * out)825*412f47f9SXin Li char *test_isless(uint32 *x, uint32 *y, uint32 *out)
826*412f47f9SXin Li {
827*412f47f9SXin Li     int result = fpcmp4(x, y);
828*412f47f9SXin Li     *out = (result == -1);
829*412f47f9SXin Li     return result == -3 ? "i" : NULL;
830*412f47f9SXin Li }
831*412f47f9SXin Li 
test_islessequal(uint32 * x,uint32 * y,uint32 * out)832*412f47f9SXin Li char *test_islessequal(uint32 *x, uint32 *y, uint32 *out)
833*412f47f9SXin Li {
834*412f47f9SXin Li     int result = fpcmp4(x, y);
835*412f47f9SXin Li     *out = (result == -1) || (result == 0);
836*412f47f9SXin Li     return result == -3 ? "i" : NULL;
837*412f47f9SXin Li }
838*412f47f9SXin Li 
test_islessgreater(uint32 * x,uint32 * y,uint32 * out)839*412f47f9SXin Li char *test_islessgreater(uint32 *x, uint32 *y, uint32 *out)
840*412f47f9SXin Li {
841*412f47f9SXin Li     int result = fpcmp4(x, y);
842*412f47f9SXin Li     *out = (result == -1) || (result == 1);
843*412f47f9SXin Li     return result == -3 ? "i" : NULL;
844*412f47f9SXin Li }
845*412f47f9SXin Li 
test_isunordered(uint32 * x,uint32 * y,uint32 * out)846*412f47f9SXin Li char *test_isunordered(uint32 *x, uint32 *y, uint32 *out)
847*412f47f9SXin Li {
848*412f47f9SXin Li     int normal = 0;
849*412f47f9SXin Li     int result = fpcmp4(x, y);
850*412f47f9SXin Li 
851*412f47f9SXin Li     test_isnormal(x, out);
852*412f47f9SXin Li     normal |= *out;
853*412f47f9SXin Li     test_isnormal(y, out);
854*412f47f9SXin Li     normal |= *out;
855*412f47f9SXin Li     *out = (result == -2) || (result == -3);
856*412f47f9SXin Li     return result == -3 ? "i" : NULL;
857*412f47f9SXin Li }
858*412f47f9SXin Li 
test_isgreaterf(uint32 * x,uint32 * y,uint32 * out)859*412f47f9SXin Li char *test_isgreaterf(uint32 *x, uint32 *y, uint32 *out)
860*412f47f9SXin Li {
861*412f47f9SXin Li     int result = fpcmp4f(x, y);
862*412f47f9SXin Li     *out = (result == 1);
863*412f47f9SXin Li     return result == -3 ? "i" : NULL;
864*412f47f9SXin Li }
865*412f47f9SXin Li 
test_isgreaterequalf(uint32 * x,uint32 * y,uint32 * out)866*412f47f9SXin Li char *test_isgreaterequalf(uint32 *x, uint32 *y, uint32 *out)
867*412f47f9SXin Li {
868*412f47f9SXin Li     int result = fpcmp4f(x, y);
869*412f47f9SXin Li     *out = (result >= 0);
870*412f47f9SXin Li     return result == -3 ? "i" : NULL;
871*412f47f9SXin Li }
872*412f47f9SXin Li 
test_islessf(uint32 * x,uint32 * y,uint32 * out)873*412f47f9SXin Li char *test_islessf(uint32 *x, uint32 *y, uint32 *out)
874*412f47f9SXin Li {
875*412f47f9SXin Li     int result = fpcmp4f(x, y);
876*412f47f9SXin Li     *out = (result == -1);
877*412f47f9SXin Li     return result == -3 ? "i" : NULL;
878*412f47f9SXin Li }
879*412f47f9SXin Li 
test_islessequalf(uint32 * x,uint32 * y,uint32 * out)880*412f47f9SXin Li char *test_islessequalf(uint32 *x, uint32 *y, uint32 *out)
881*412f47f9SXin Li {
882*412f47f9SXin Li     int result = fpcmp4f(x, y);
883*412f47f9SXin Li     *out = (result == -1) || (result == 0);
884*412f47f9SXin Li     return result == -3 ? "i" : NULL;
885*412f47f9SXin Li }
886*412f47f9SXin Li 
test_islessgreaterf(uint32 * x,uint32 * y,uint32 * out)887*412f47f9SXin Li char *test_islessgreaterf(uint32 *x, uint32 *y, uint32 *out)
888*412f47f9SXin Li {
889*412f47f9SXin Li     int result = fpcmp4f(x, y);
890*412f47f9SXin Li     *out = (result == -1) || (result == 1);
891*412f47f9SXin Li     return result == -3 ? "i" : NULL;
892*412f47f9SXin Li }
893*412f47f9SXin Li 
test_isunorderedf(uint32 * x,uint32 * y,uint32 * out)894*412f47f9SXin Li char *test_isunorderedf(uint32 *x, uint32 *y, uint32 *out)
895*412f47f9SXin Li {
896*412f47f9SXin Li     int normal = 0;
897*412f47f9SXin Li     int result = fpcmp4f(x, y);
898*412f47f9SXin Li 
899*412f47f9SXin Li     test_isnormalf(x, out);
900*412f47f9SXin Li     normal |= *out;
901*412f47f9SXin Li     test_isnormalf(y, out);
902*412f47f9SXin Li     normal |= *out;
903*412f47f9SXin Li     *out = (result == -2) || (result == -3);
904*412f47f9SXin Li     return result == -3 ? "i" : NULL;
905*412f47f9SXin Li }
906