xref: /freebsd-src/contrib/arm-optimized-routines/math/test/rtest/semi.c (revision 072a4ba82a01476eaee33781ccd241033eefcf0b)
131914882SAlex Richardson /*
231914882SAlex Richardson  * semi.c: test implementations of mathlib seminumerical functions
331914882SAlex Richardson  *
431914882SAlex Richardson  * Copyright (c) 1999-2019, Arm Limited.
5*072a4ba8SAndrew Turner  * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
631914882SAlex Richardson  */
731914882SAlex Richardson 
831914882SAlex Richardson #include <stdio.h>
931914882SAlex Richardson #include "semi.h"
1031914882SAlex Richardson 
test_rint(uint32 * in,uint32 * out,int isfloor,int isceil)1131914882SAlex Richardson static void test_rint(uint32 *in, uint32 *out,
1231914882SAlex Richardson                        int isfloor, int isceil) {
1331914882SAlex Richardson     int sign = in[0] & 0x80000000;
1431914882SAlex Richardson     int roundup = (isfloor && sign) || (isceil && !sign);
1531914882SAlex Richardson     uint32 xh, xl, roundword;
1631914882SAlex Richardson     int ex = (in[0] >> 20) & 0x7FF;    /* exponent */
1731914882SAlex Richardson     int i;
1831914882SAlex Richardson 
1931914882SAlex Richardson     if ((ex > 0x3ff + 52 - 1) ||     /* things this big can't be fractional */
2031914882SAlex Richardson         ((in[0] & 0x7FFFFFFF) == 0 && in[1] == 0)) {   /* zero */
2131914882SAlex Richardson         /* NaN, Inf, a large integer, or zero: just return the input */
2231914882SAlex Richardson         out[0] = in[0];
2331914882SAlex Richardson         out[1] = in[1];
2431914882SAlex Richardson         return;
2531914882SAlex Richardson     }
2631914882SAlex Richardson 
2731914882SAlex Richardson     /*
2831914882SAlex Richardson      * Special case: ex < 0x3ff, ie our number is in (0,1). Return
2931914882SAlex Richardson      * 1 or 0 according to roundup.
3031914882SAlex Richardson      */
3131914882SAlex Richardson     if (ex < 0x3ff) {
3231914882SAlex Richardson         out[0] = sign | (roundup ? 0x3FF00000 : 0);
3331914882SAlex Richardson         out[1] = 0;
3431914882SAlex Richardson         return;
3531914882SAlex Richardson     }
3631914882SAlex Richardson 
3731914882SAlex Richardson     /*
3831914882SAlex Richardson      * We're not short of time here, so we'll do this the hideously
3931914882SAlex Richardson      * inefficient way. Shift bit by bit so that the units place is
4031914882SAlex Richardson      * somewhere predictable, round, and shift back again.
4131914882SAlex Richardson      */
4231914882SAlex Richardson     xh = in[0];
4331914882SAlex Richardson     xl = in[1];
4431914882SAlex Richardson     roundword = 0;
4531914882SAlex Richardson     for (i = ex; i < 0x3ff + 52; i++) {
4631914882SAlex Richardson         if (roundword & 1)
4731914882SAlex Richardson             roundword |= 2;            /* preserve sticky bit */
4831914882SAlex Richardson         roundword = (roundword >> 1) | ((xl & 1) << 31);
4931914882SAlex Richardson         xl = (xl >> 1) | ((xh & 1) << 31);
5031914882SAlex Richardson         xh = xh >> 1;
5131914882SAlex Richardson     }
5231914882SAlex Richardson     if (roundword && roundup) {
5331914882SAlex Richardson         xl++;
5431914882SAlex Richardson         xh += (xl==0);
5531914882SAlex Richardson     }
5631914882SAlex Richardson     for (i = ex; i < 0x3ff + 52; i++) {
5731914882SAlex Richardson         xh = (xh << 1) | ((xl >> 31) & 1);
5831914882SAlex Richardson         xl = (xl & 0x7FFFFFFF) << 1;
5931914882SAlex Richardson     }
6031914882SAlex Richardson     out[0] = xh;
6131914882SAlex Richardson     out[1] = xl;
6231914882SAlex Richardson }
6331914882SAlex Richardson 
test_ceil(uint32 * in,uint32 * out)6431914882SAlex Richardson char *test_ceil(uint32 *in, uint32 *out) {
6531914882SAlex Richardson     test_rint(in, out, 0, 1);
6631914882SAlex Richardson     return NULL;
6731914882SAlex Richardson }
6831914882SAlex Richardson 
test_floor(uint32 * in,uint32 * out)6931914882SAlex Richardson char *test_floor(uint32 *in, uint32 *out) {
7031914882SAlex Richardson     test_rint(in, out, 1, 0);
7131914882SAlex Richardson     return NULL;
7231914882SAlex Richardson }
7331914882SAlex Richardson 
test_rintf(uint32 * in,uint32 * out,int isfloor,int isceil)7431914882SAlex Richardson static void test_rintf(uint32 *in, uint32 *out,
7531914882SAlex Richardson                        int isfloor, int isceil) {
7631914882SAlex Richardson     int sign = *in & 0x80000000;
7731914882SAlex Richardson     int roundup = (isfloor && sign) || (isceil && !sign);
7831914882SAlex Richardson     uint32 x, roundword;
7931914882SAlex Richardson     int ex = (*in >> 23) & 0xFF;       /* exponent */
8031914882SAlex Richardson     int i;
8131914882SAlex Richardson 
8231914882SAlex Richardson     if ((ex > 0x7f + 23 - 1) ||      /* things this big can't be fractional */
8331914882SAlex Richardson         (*in & 0x7FFFFFFF) == 0) {     /* zero */
8431914882SAlex Richardson         /* NaN, Inf, a large integer, or zero: just return the input */
8531914882SAlex Richardson         *out = *in;
8631914882SAlex Richardson         return;
8731914882SAlex Richardson     }
8831914882SAlex Richardson 
8931914882SAlex Richardson     /*
9031914882SAlex Richardson      * Special case: ex < 0x7f, ie our number is in (0,1). Return
9131914882SAlex Richardson      * 1 or 0 according to roundup.
9231914882SAlex Richardson      */
9331914882SAlex Richardson     if (ex < 0x7f) {
9431914882SAlex Richardson         *out = sign | (roundup ? 0x3F800000 : 0);
9531914882SAlex Richardson         return;
9631914882SAlex Richardson     }
9731914882SAlex Richardson 
9831914882SAlex Richardson     /*
9931914882SAlex Richardson      * We're not short of time here, so we'll do this the hideously
10031914882SAlex Richardson      * inefficient way. Shift bit by bit so that the units place is
10131914882SAlex Richardson      * somewhere predictable, round, and shift back again.
10231914882SAlex Richardson      */
10331914882SAlex Richardson     x = *in;
10431914882SAlex Richardson     roundword = 0;
10531914882SAlex Richardson     for (i = ex; i < 0x7F + 23; i++) {
10631914882SAlex Richardson         if (roundword & 1)
10731914882SAlex Richardson             roundword |= 2;            /* preserve sticky bit */
10831914882SAlex Richardson         roundword = (roundword >> 1) | ((x & 1) << 31);
10931914882SAlex Richardson         x = x >> 1;
11031914882SAlex Richardson     }
11131914882SAlex Richardson     if (roundword && roundup) {
11231914882SAlex Richardson         x++;
11331914882SAlex Richardson     }
11431914882SAlex Richardson     for (i = ex; i < 0x7F + 23; i++) {
11531914882SAlex Richardson         x = x << 1;
11631914882SAlex Richardson     }
11731914882SAlex Richardson     *out = x;
11831914882SAlex Richardson }
11931914882SAlex Richardson 
test_ceilf(uint32 * in,uint32 * out)12031914882SAlex Richardson char *test_ceilf(uint32 *in, uint32 *out) {
12131914882SAlex Richardson     test_rintf(in, out, 0, 1);
12231914882SAlex Richardson     return NULL;
12331914882SAlex Richardson }
12431914882SAlex Richardson 
test_floorf(uint32 * in,uint32 * out)12531914882SAlex Richardson char *test_floorf(uint32 *in, uint32 *out) {
12631914882SAlex Richardson     test_rintf(in, out, 1, 0);
12731914882SAlex Richardson     return NULL;
12831914882SAlex Richardson }
12931914882SAlex Richardson 
test_fmod(uint32 * a,uint32 * b,uint32 * out)13031914882SAlex Richardson char *test_fmod(uint32 *a, uint32 *b, uint32 *out) {
13131914882SAlex Richardson     int sign;
13231914882SAlex Richardson     int32 aex, bex;
13331914882SAlex Richardson     uint32 am[2], bm[2];
13431914882SAlex Richardson 
13531914882SAlex Richardson     if (((a[0] & 0x7FFFFFFF) << 1) + !!a[1] > 0xFFE00000 ||
13631914882SAlex Richardson         ((b[0] & 0x7FFFFFFF) << 1) + !!b[1] > 0xFFE00000) {
13731914882SAlex Richardson         /* a or b is NaN: return QNaN, optionally with IVO */
13831914882SAlex Richardson         uint32 an, bn;
13931914882SAlex Richardson         out[0] = 0x7ff80000;
14031914882SAlex Richardson         out[1] = 1;
14131914882SAlex Richardson         an = ((a[0] & 0x7FFFFFFF) << 1) + !!a[1];
14231914882SAlex Richardson         bn = ((b[0] & 0x7FFFFFFF) << 1) + !!b[1];
14331914882SAlex Richardson         if ((an > 0xFFE00000 && an < 0xFFF00000) ||
14431914882SAlex Richardson             (bn > 0xFFE00000 && bn < 0xFFF00000))
14531914882SAlex Richardson             return "i";                /* at least one SNaN: IVO */
14631914882SAlex Richardson         else
14731914882SAlex Richardson             return NULL;               /* no SNaNs, but at least 1 QNaN */
14831914882SAlex Richardson     }
14931914882SAlex Richardson     if ((b[0] & 0x7FFFFFFF) == 0 && b[1] == 0) {   /* b==0: EDOM */
15031914882SAlex Richardson         out[0] = 0x7ff80000;
15131914882SAlex Richardson         out[1] = 1;
15231914882SAlex Richardson         return "EDOM status=i";
15331914882SAlex Richardson     }
15431914882SAlex Richardson     if ((a[0] & 0x7FF00000) == 0x7FF00000) {   /* a==Inf: EDOM */
15531914882SAlex Richardson         out[0] = 0x7ff80000;
15631914882SAlex Richardson         out[1] = 1;
15731914882SAlex Richardson         return "EDOM status=i";
15831914882SAlex Richardson     }
15931914882SAlex Richardson     if ((b[0] & 0x7FF00000) == 0x7FF00000) {   /* b==Inf: return a */
16031914882SAlex Richardson         out[0] = a[0];
16131914882SAlex Richardson         out[1] = a[1];
16231914882SAlex Richardson         return NULL;
16331914882SAlex Richardson     }
16431914882SAlex Richardson     if ((a[0] & 0x7FFFFFFF) == 0 && a[1] == 0) {   /* a==0: return a */
16531914882SAlex Richardson         out[0] = a[0];
16631914882SAlex Richardson         out[1] = a[1];
16731914882SAlex Richardson         return NULL;
16831914882SAlex Richardson     }
16931914882SAlex Richardson 
17031914882SAlex Richardson     /*
17131914882SAlex Richardson      * OK. That's the special cases cleared out of the way. Now we
17231914882SAlex Richardson      * have finite (though not necessarily normal) a and b.
17331914882SAlex Richardson      */
17431914882SAlex Richardson     sign = a[0] & 0x80000000;          /* we discard sign of b */
17531914882SAlex Richardson     test_frexp(a, am, (uint32 *)&aex);
17631914882SAlex Richardson     test_frexp(b, bm, (uint32 *)&bex);
17731914882SAlex Richardson     am[0] &= 0xFFFFF, am[0] |= 0x100000;
17831914882SAlex Richardson     bm[0] &= 0xFFFFF, bm[0] |= 0x100000;
17931914882SAlex Richardson 
18031914882SAlex Richardson     while (aex >= bex) {
18131914882SAlex Richardson         if (am[0] > bm[0] || (am[0] == bm[0] && am[1] >= bm[1])) {
18231914882SAlex Richardson             am[1] -= bm[1];
18331914882SAlex Richardson             am[0] = am[0] - bm[0] - (am[1] > ~bm[1]);
18431914882SAlex Richardson         }
18531914882SAlex Richardson         if (aex > bex) {
18631914882SAlex Richardson             am[0] = (am[0] << 1) | ((am[1] & 0x80000000) >> 31);
18731914882SAlex Richardson             am[1] <<= 1;
18831914882SAlex Richardson             aex--;
18931914882SAlex Richardson         } else
19031914882SAlex Richardson             break;
19131914882SAlex Richardson     }
19231914882SAlex Richardson 
19331914882SAlex Richardson     /*
19431914882SAlex Richardson      * Renormalise final result; this can be cunningly done by
19531914882SAlex Richardson      * passing a denormal to ldexp.
19631914882SAlex Richardson      */
19731914882SAlex Richardson     aex += 0x3fd;
19831914882SAlex Richardson     am[0] |= sign;
19931914882SAlex Richardson     test_ldexp(am, (uint32 *)&aex, out);
20031914882SAlex Richardson 
20131914882SAlex Richardson     return NULL;                       /* FIXME */
20231914882SAlex Richardson }
20331914882SAlex Richardson 
test_fmodf(uint32 * a,uint32 * b,uint32 * out)20431914882SAlex Richardson char *test_fmodf(uint32 *a, uint32 *b, uint32 *out) {
20531914882SAlex Richardson     int sign;
20631914882SAlex Richardson     int32 aex, bex;
20731914882SAlex Richardson     uint32 am, bm;
20831914882SAlex Richardson 
20931914882SAlex Richardson     if ((*a & 0x7FFFFFFF) > 0x7F800000 ||
21031914882SAlex Richardson         (*b & 0x7FFFFFFF) > 0x7F800000) {
21131914882SAlex Richardson         /* a or b is NaN: return QNaN, optionally with IVO */
21231914882SAlex Richardson         uint32 an, bn;
21331914882SAlex Richardson         *out = 0x7fc00001;
21431914882SAlex Richardson         an = *a & 0x7FFFFFFF;
21531914882SAlex Richardson         bn = *b & 0x7FFFFFFF;
21631914882SAlex Richardson         if ((an > 0x7f800000 && an < 0x7fc00000) ||
21731914882SAlex Richardson             (bn > 0x7f800000 && bn < 0x7fc00000))
21831914882SAlex Richardson             return "i";                /* at least one SNaN: IVO */
21931914882SAlex Richardson         else
22031914882SAlex Richardson             return NULL;               /* no SNaNs, but at least 1 QNaN */
22131914882SAlex Richardson     }
22231914882SAlex Richardson     if ((*b & 0x7FFFFFFF) == 0) {      /* b==0: EDOM */
22331914882SAlex Richardson         *out = 0x7fc00001;
22431914882SAlex Richardson         return "EDOM status=i";
22531914882SAlex Richardson     }
22631914882SAlex Richardson     if ((*a & 0x7F800000) == 0x7F800000) {   /* a==Inf: EDOM */
22731914882SAlex Richardson         *out = 0x7fc00001;
22831914882SAlex Richardson         return "EDOM status=i";
22931914882SAlex Richardson     }
23031914882SAlex Richardson     if ((*b & 0x7F800000) == 0x7F800000) {   /* b==Inf: return a */
23131914882SAlex Richardson         *out = *a;
23231914882SAlex Richardson         return NULL;
23331914882SAlex Richardson     }
23431914882SAlex Richardson     if ((*a & 0x7FFFFFFF) == 0) {      /* a==0: return a */
23531914882SAlex Richardson         *out = *a;
23631914882SAlex Richardson         return NULL;
23731914882SAlex Richardson     }
23831914882SAlex Richardson 
23931914882SAlex Richardson     /*
24031914882SAlex Richardson      * OK. That's the special cases cleared out of the way. Now we
24131914882SAlex Richardson      * have finite (though not necessarily normal) a and b.
24231914882SAlex Richardson      */
24331914882SAlex Richardson     sign = a[0] & 0x80000000;          /* we discard sign of b */
24431914882SAlex Richardson     test_frexpf(a, &am, (uint32 *)&aex);
24531914882SAlex Richardson     test_frexpf(b, &bm, (uint32 *)&bex);
24631914882SAlex Richardson     am &= 0x7FFFFF, am |= 0x800000;
24731914882SAlex Richardson     bm &= 0x7FFFFF, bm |= 0x800000;
24831914882SAlex Richardson 
24931914882SAlex Richardson     while (aex >= bex) {
25031914882SAlex Richardson         if (am >= bm) {
25131914882SAlex Richardson             am -= bm;
25231914882SAlex Richardson         }
25331914882SAlex Richardson         if (aex > bex) {
25431914882SAlex Richardson             am <<= 1;
25531914882SAlex Richardson             aex--;
25631914882SAlex Richardson         } else
25731914882SAlex Richardson             break;
25831914882SAlex Richardson     }
25931914882SAlex Richardson 
26031914882SAlex Richardson     /*
26131914882SAlex Richardson      * Renormalise final result; this can be cunningly done by
26231914882SAlex Richardson      * passing a denormal to ldexp.
26331914882SAlex Richardson      */
26431914882SAlex Richardson     aex += 0x7d;
26531914882SAlex Richardson     am |= sign;
26631914882SAlex Richardson     test_ldexpf(&am, (uint32 *)&aex, out);
26731914882SAlex Richardson 
26831914882SAlex Richardson     return NULL;                       /* FIXME */
26931914882SAlex Richardson }
27031914882SAlex Richardson 
test_ldexp(uint32 * x,uint32 * np,uint32 * out)27131914882SAlex Richardson char *test_ldexp(uint32 *x, uint32 *np, uint32 *out) {
27231914882SAlex Richardson     int n = *np;
27331914882SAlex Richardson     int32 n2;
27431914882SAlex Richardson     uint32 y[2];
27531914882SAlex Richardson     int ex = (x[0] >> 20) & 0x7FF;     /* exponent */
27631914882SAlex Richardson     int sign = x[0] & 0x80000000;
27731914882SAlex Richardson 
27831914882SAlex Richardson     if (ex == 0x7FF) {                 /* inf/NaN; just return x */
27931914882SAlex Richardson         out[0] = x[0];
28031914882SAlex Richardson         out[1] = x[1];
28131914882SAlex Richardson         return NULL;
28231914882SAlex Richardson     }
28331914882SAlex Richardson     if ((x[0] & 0x7FFFFFFF) == 0 && x[1] == 0) {   /* zero: return x */
28431914882SAlex Richardson         out[0] = x[0];
28531914882SAlex Richardson         out[1] = x[1];
28631914882SAlex Richardson         return NULL;
28731914882SAlex Richardson     }
28831914882SAlex Richardson 
28931914882SAlex Richardson     test_frexp(x, y, (uint32 *)&n2);
29031914882SAlex Richardson     ex = n + n2;
29131914882SAlex Richardson     if (ex > 0x400) {                  /* overflow */
29231914882SAlex Richardson         out[0] = sign | 0x7FF00000;
29331914882SAlex Richardson         out[1] = 0;
29431914882SAlex Richardson         return "overflow";
29531914882SAlex Richardson     }
29631914882SAlex Richardson     /*
29731914882SAlex Richardson      * Underflow. 2^-1074 is 00000000.00000001; so if ex == -1074
29831914882SAlex Richardson      * then we have something [2^-1075,2^-1074). Under round-to-
29931914882SAlex Richardson      * nearest-even, this whole interval rounds up to 2^-1074,
30031914882SAlex Richardson      * except for the bottom endpoint which rounds to even and is
30131914882SAlex Richardson      * an underflow condition.
30231914882SAlex Richardson      *
30331914882SAlex Richardson      * So, ex < -1074 is definite underflow, and ex == -1074 is
30431914882SAlex Richardson      * underflow iff all mantissa bits are zero.
30531914882SAlex Richardson      */
30631914882SAlex Richardson     if (ex < -1074 || (ex == -1074 && (y[0] & 0xFFFFF) == 0 && y[1] == 0)) {
30731914882SAlex Richardson         out[0] = sign;                 /* underflow: correctly signed zero */
30831914882SAlex Richardson         out[1] = 0;
30931914882SAlex Richardson         return "underflow";
31031914882SAlex Richardson     }
31131914882SAlex Richardson 
31231914882SAlex Richardson     /*
31331914882SAlex Richardson      * No overflow or underflow; should be nice and simple, unless
31431914882SAlex Richardson      * we have to denormalise and round the result.
31531914882SAlex Richardson      */
31631914882SAlex Richardson     if (ex < -1021) {                  /* denormalise and round */
31731914882SAlex Richardson         uint32 roundword;
31831914882SAlex Richardson         y[0] &= 0x000FFFFF;
31931914882SAlex Richardson         y[0] |= 0x00100000;            /* set leading bit */
32031914882SAlex Richardson         roundword = 0;
32131914882SAlex Richardson         while (ex < -1021) {
32231914882SAlex Richardson             if (roundword & 1)
32331914882SAlex Richardson                 roundword |= 2;        /* preserve sticky bit */
32431914882SAlex Richardson             roundword = (roundword >> 1) | ((y[1] & 1) << 31);
32531914882SAlex Richardson             y[1] = (y[1] >> 1) | ((y[0] & 1) << 31);
32631914882SAlex Richardson             y[0] = y[0] >> 1;
32731914882SAlex Richardson             ex++;
32831914882SAlex Richardson         }
32931914882SAlex Richardson         if (roundword > 0x80000000 ||  /* round up */
33031914882SAlex Richardson             (roundword == 0x80000000 && (y[1] & 1))) {  /* round up to even */
33131914882SAlex Richardson             y[1]++;
33231914882SAlex Richardson             y[0] += (y[1] == 0);
33331914882SAlex Richardson         }
33431914882SAlex Richardson         out[0] = sign | y[0];
33531914882SAlex Richardson         out[1] = y[1];
33631914882SAlex Richardson         /* Proper ERANGE underflow was handled earlier, but we still
33731914882SAlex Richardson          * expect an IEEE Underflow exception if this partially
33831914882SAlex Richardson          * underflowed result is not exact. */
33931914882SAlex Richardson         if (roundword)
34031914882SAlex Richardson             return "u";
34131914882SAlex Richardson         return NULL;                   /* underflow was handled earlier */
34231914882SAlex Richardson     } else {
34331914882SAlex Richardson         out[0] = y[0] + (ex << 20);
34431914882SAlex Richardson         out[1] = y[1];
34531914882SAlex Richardson         return NULL;
34631914882SAlex Richardson     }
34731914882SAlex Richardson }
34831914882SAlex Richardson 
test_ldexpf(uint32 * x,uint32 * np,uint32 * out)34931914882SAlex Richardson char *test_ldexpf(uint32 *x, uint32 *np, uint32 *out) {
35031914882SAlex Richardson     int n = *np;
35131914882SAlex Richardson     int32 n2;
35231914882SAlex Richardson     uint32 y;
35331914882SAlex Richardson     int ex = (*x >> 23) & 0xFF;     /* exponent */
35431914882SAlex Richardson     int sign = *x & 0x80000000;
35531914882SAlex Richardson 
35631914882SAlex Richardson     if (ex == 0xFF) {                 /* inf/NaN; just return x */
35731914882SAlex Richardson         *out = *x;
35831914882SAlex Richardson         return NULL;
35931914882SAlex Richardson     }
36031914882SAlex Richardson     if ((*x & 0x7FFFFFFF) == 0) {      /* zero: return x */
36131914882SAlex Richardson         *out = *x;
36231914882SAlex Richardson         return NULL;
36331914882SAlex Richardson     }
36431914882SAlex Richardson 
36531914882SAlex Richardson     test_frexpf(x, &y, (uint32 *)&n2);
36631914882SAlex Richardson     ex = n + n2;
36731914882SAlex Richardson     if (ex > 0x80) {                  /* overflow */
36831914882SAlex Richardson         *out = sign | 0x7F800000;
36931914882SAlex Richardson         return "overflow";
37031914882SAlex Richardson     }
37131914882SAlex Richardson     /*
37231914882SAlex Richardson      * Underflow. 2^-149 is 00000001; so if ex == -149 then we have
37331914882SAlex Richardson      * something [2^-150,2^-149). Under round-to- nearest-even,
37431914882SAlex Richardson      * this whole interval rounds up to 2^-149, except for the
37531914882SAlex Richardson      * bottom endpoint which rounds to even and is an underflow
37631914882SAlex Richardson      * condition.
37731914882SAlex Richardson      *
37831914882SAlex Richardson      * So, ex < -149 is definite underflow, and ex == -149 is
37931914882SAlex Richardson      * underflow iff all mantissa bits are zero.
38031914882SAlex Richardson      */
38131914882SAlex Richardson     if (ex < -149 || (ex == -149 && (y & 0x7FFFFF) == 0)) {
38231914882SAlex Richardson         *out = sign;                 /* underflow: correctly signed zero */
38331914882SAlex Richardson         return "underflow";
38431914882SAlex Richardson     }
38531914882SAlex Richardson 
38631914882SAlex Richardson     /*
38731914882SAlex Richardson      * No overflow or underflow; should be nice and simple, unless
38831914882SAlex Richardson      * we have to denormalise and round the result.
38931914882SAlex Richardson      */
39031914882SAlex Richardson     if (ex < -125) {                  /* denormalise and round */
39131914882SAlex Richardson         uint32 roundword;
39231914882SAlex Richardson         y &= 0x007FFFFF;
39331914882SAlex Richardson         y |= 0x00800000;               /* set leading bit */
39431914882SAlex Richardson         roundword = 0;
39531914882SAlex Richardson         while (ex < -125) {
39631914882SAlex Richardson             if (roundword & 1)
39731914882SAlex Richardson                 roundword |= 2;        /* preserve sticky bit */
39831914882SAlex Richardson             roundword = (roundword >> 1) | ((y & 1) << 31);
39931914882SAlex Richardson             y = y >> 1;
40031914882SAlex Richardson             ex++;
40131914882SAlex Richardson         }
40231914882SAlex Richardson         if (roundword > 0x80000000 ||  /* round up */
40331914882SAlex Richardson             (roundword == 0x80000000 && (y & 1))) {  /* round up to even */
40431914882SAlex Richardson             y++;
40531914882SAlex Richardson         }
40631914882SAlex Richardson         *out = sign | y;
40731914882SAlex Richardson         /* Proper ERANGE underflow was handled earlier, but we still
40831914882SAlex Richardson          * expect an IEEE Underflow exception if this partially
40931914882SAlex Richardson          * underflowed result is not exact. */
41031914882SAlex Richardson         if (roundword)
41131914882SAlex Richardson             return "u";
41231914882SAlex Richardson         return NULL;                   /* underflow was handled earlier */
41331914882SAlex Richardson     } else {
41431914882SAlex Richardson         *out = y + (ex << 23);
41531914882SAlex Richardson         return NULL;
41631914882SAlex Richardson     }
41731914882SAlex Richardson }
41831914882SAlex Richardson 
test_frexp(uint32 * x,uint32 * out,uint32 * nout)41931914882SAlex Richardson char *test_frexp(uint32 *x, uint32 *out, uint32 *nout) {
42031914882SAlex Richardson     int ex = (x[0] >> 20) & 0x7FF;     /* exponent */
42131914882SAlex Richardson     if (ex == 0x7FF) {                 /* inf/NaN; return x/0 */
42231914882SAlex Richardson         out[0] = x[0];
42331914882SAlex Richardson         out[1] = x[1];
42431914882SAlex Richardson         nout[0] = 0;
42531914882SAlex Richardson         return NULL;
42631914882SAlex Richardson     }
42731914882SAlex Richardson     if (ex == 0) {                     /* denormals/zeros */
42831914882SAlex Richardson         int sign;
42931914882SAlex Richardson         uint32 xh, xl;
43031914882SAlex Richardson         if ((x[0] & 0x7FFFFFFF) == 0 && x[1] == 0) {
43131914882SAlex Richardson             /* zero: return x/0 */
43231914882SAlex Richardson             out[0] = x[0];
43331914882SAlex Richardson             out[1] = x[1];
43431914882SAlex Richardson             nout[0] = 0;
43531914882SAlex Richardson             return NULL;
43631914882SAlex Richardson         }
43731914882SAlex Richardson         sign = x[0] & 0x80000000;
43831914882SAlex Richardson         xh = x[0] & 0x7FFFFFFF;
43931914882SAlex Richardson         xl = x[1];
44031914882SAlex Richardson         ex = 1;
44131914882SAlex Richardson         while (!(xh & 0x100000)) {
44231914882SAlex Richardson             ex--;
44331914882SAlex Richardson             xh = (xh << 1) | ((xl >> 31) & 1);
44431914882SAlex Richardson             xl = (xl & 0x7FFFFFFF) << 1;
44531914882SAlex Richardson         }
44631914882SAlex Richardson         out[0] = sign | 0x3FE00000 | (xh & 0xFFFFF);
44731914882SAlex Richardson         out[1] = xl;
44831914882SAlex Richardson         nout[0] = ex - 0x3FE;
44931914882SAlex Richardson         return NULL;
45031914882SAlex Richardson     }
45131914882SAlex Richardson     out[0] = 0x3FE00000 | (x[0] & 0x800FFFFF);
45231914882SAlex Richardson     out[1] = x[1];
45331914882SAlex Richardson     nout[0] = ex - 0x3FE;
45431914882SAlex Richardson     return NULL;                       /* ordinary number; no error */
45531914882SAlex Richardson }
45631914882SAlex Richardson 
test_frexpf(uint32 * x,uint32 * out,uint32 * nout)45731914882SAlex Richardson char *test_frexpf(uint32 *x, uint32 *out, uint32 *nout) {
45831914882SAlex Richardson     int ex = (*x >> 23) & 0xFF;        /* exponent */
45931914882SAlex Richardson     if (ex == 0xFF) {                  /* inf/NaN; return x/0 */
46031914882SAlex Richardson         *out = *x;
46131914882SAlex Richardson         nout[0] = 0;
46231914882SAlex Richardson         return NULL;
46331914882SAlex Richardson     }
46431914882SAlex Richardson     if (ex == 0) {                     /* denormals/zeros */
46531914882SAlex Richardson         int sign;
46631914882SAlex Richardson         uint32 xv;
46731914882SAlex Richardson         if ((*x & 0x7FFFFFFF) == 0) {
46831914882SAlex Richardson             /* zero: return x/0 */
46931914882SAlex Richardson             *out = *x;
47031914882SAlex Richardson             nout[0] = 0;
47131914882SAlex Richardson             return NULL;
47231914882SAlex Richardson         }
47331914882SAlex Richardson         sign = *x & 0x80000000;
47431914882SAlex Richardson         xv = *x & 0x7FFFFFFF;
47531914882SAlex Richardson         ex = 1;
47631914882SAlex Richardson         while (!(xv & 0x800000)) {
47731914882SAlex Richardson             ex--;
47831914882SAlex Richardson             xv = xv << 1;
47931914882SAlex Richardson         }
48031914882SAlex Richardson         *out = sign | 0x3F000000 | (xv & 0x7FFFFF);
48131914882SAlex Richardson         nout[0] = ex - 0x7E;
48231914882SAlex Richardson         return NULL;
48331914882SAlex Richardson     }
48431914882SAlex Richardson     *out = 0x3F000000 | (*x & 0x807FFFFF);
48531914882SAlex Richardson     nout[0] = ex - 0x7E;
48631914882SAlex Richardson     return NULL;                       /* ordinary number; no error */
48731914882SAlex Richardson }
48831914882SAlex Richardson 
test_modf(uint32 * x,uint32 * fout,uint32 * iout)48931914882SAlex Richardson char *test_modf(uint32 *x, uint32 *fout, uint32 *iout) {
49031914882SAlex Richardson     int ex = (x[0] >> 20) & 0x7FF;     /* exponent */
49131914882SAlex Richardson     int sign = x[0] & 0x80000000;
49231914882SAlex Richardson     uint32 fh, fl;
49331914882SAlex Richardson 
49431914882SAlex Richardson     if (((x[0] & 0x7FFFFFFF) | (!!x[1])) > 0x7FF00000) {
49531914882SAlex Richardson         /*
49631914882SAlex Richardson          * NaN input: return the same in _both_ outputs.
49731914882SAlex Richardson          */
49831914882SAlex Richardson         fout[0] = iout[0] = x[0];
49931914882SAlex Richardson         fout[1] = iout[1] = x[1];
50031914882SAlex Richardson         return NULL;
50131914882SAlex Richardson     }
50231914882SAlex Richardson 
50331914882SAlex Richardson     test_rint(x, iout, 0, 0);
50431914882SAlex Richardson     fh = x[0] - iout[0];
50531914882SAlex Richardson     fl = x[1] - iout[1];
50631914882SAlex Richardson     if (!fh && !fl) {                  /* no fraction part */
50731914882SAlex Richardson         fout[0] = sign;
50831914882SAlex Richardson         fout[1] = 0;
50931914882SAlex Richardson         return NULL;
51031914882SAlex Richardson     }
51131914882SAlex Richardson     if (!(iout[0] & 0x7FFFFFFF) && !iout[1]) {   /* no integer part */
51231914882SAlex Richardson         fout[0] = x[0];
51331914882SAlex Richardson         fout[1] = x[1];
51431914882SAlex Richardson         return NULL;
51531914882SAlex Richardson     }
51631914882SAlex Richardson     while (!(fh & 0x100000)) {
51731914882SAlex Richardson         ex--;
51831914882SAlex Richardson         fh = (fh << 1) | ((fl >> 31) & 1);
51931914882SAlex Richardson         fl = (fl & 0x7FFFFFFF) << 1;
52031914882SAlex Richardson     }
52131914882SAlex Richardson     fout[0] = sign | (ex << 20) | (fh & 0xFFFFF);
52231914882SAlex Richardson     fout[1] = fl;
52331914882SAlex Richardson     return NULL;
52431914882SAlex Richardson }
52531914882SAlex Richardson 
test_modff(uint32 * x,uint32 * fout,uint32 * iout)52631914882SAlex Richardson char *test_modff(uint32 *x, uint32 *fout, uint32 *iout) {
52731914882SAlex Richardson     int ex = (*x >> 23) & 0xFF;        /* exponent */
52831914882SAlex Richardson     int sign = *x & 0x80000000;
52931914882SAlex Richardson     uint32 f;
53031914882SAlex Richardson 
53131914882SAlex Richardson     if ((*x & 0x7FFFFFFF) > 0x7F800000) {
53231914882SAlex Richardson         /*
53331914882SAlex Richardson          * NaN input: return the same in _both_ outputs.
53431914882SAlex Richardson          */
53531914882SAlex Richardson         *fout = *iout = *x;
53631914882SAlex Richardson         return NULL;
53731914882SAlex Richardson     }
53831914882SAlex Richardson 
53931914882SAlex Richardson     test_rintf(x, iout, 0, 0);
54031914882SAlex Richardson     f = *x - *iout;
54131914882SAlex Richardson     if (!f) {                          /* no fraction part */
54231914882SAlex Richardson         *fout = sign;
54331914882SAlex Richardson         return NULL;
54431914882SAlex Richardson     }
54531914882SAlex Richardson     if (!(*iout & 0x7FFFFFFF)) {       /* no integer part */
54631914882SAlex Richardson         *fout = *x;
54731914882SAlex Richardson         return NULL;
54831914882SAlex Richardson     }
54931914882SAlex Richardson     while (!(f & 0x800000)) {
55031914882SAlex Richardson         ex--;
55131914882SAlex Richardson         f = f << 1;
55231914882SAlex Richardson     }
55331914882SAlex Richardson     *fout = sign | (ex << 23) | (f & 0x7FFFFF);
55431914882SAlex Richardson     return NULL;
55531914882SAlex Richardson }
55631914882SAlex Richardson 
test_copysign(uint32 * x,uint32 * y,uint32 * out)55731914882SAlex Richardson char *test_copysign(uint32 *x, uint32 *y, uint32 *out)
55831914882SAlex Richardson {
55931914882SAlex Richardson     int ysign = y[0] & 0x80000000;
56031914882SAlex Richardson     int xhigh = x[0] & 0x7fffffff;
56131914882SAlex Richardson 
56231914882SAlex Richardson     out[0] = ysign | xhigh;
56331914882SAlex Richardson     out[1] = x[1];
56431914882SAlex Richardson 
56531914882SAlex Richardson     /* There can be no error */
56631914882SAlex Richardson     return NULL;
56731914882SAlex Richardson }
56831914882SAlex Richardson 
test_copysignf(uint32 * x,uint32 * y,uint32 * out)56931914882SAlex Richardson char *test_copysignf(uint32 *x, uint32 *y, uint32 *out)
57031914882SAlex Richardson {
57131914882SAlex Richardson     int ysign = y[0] & 0x80000000;
57231914882SAlex Richardson     int xhigh = x[0] & 0x7fffffff;
57331914882SAlex Richardson 
57431914882SAlex Richardson     out[0] = ysign | xhigh;
57531914882SAlex Richardson 
57631914882SAlex Richardson     /* There can be no error */
57731914882SAlex Richardson     return NULL;
57831914882SAlex Richardson }
57931914882SAlex Richardson 
test_isfinite(uint32 * x,uint32 * out)58031914882SAlex Richardson char *test_isfinite(uint32 *x, uint32 *out)
58131914882SAlex Richardson {
58231914882SAlex Richardson     int xhigh = x[0];
58331914882SAlex Richardson     /* Being finite means that the exponent is not 0x7ff */
58431914882SAlex Richardson     if ((xhigh & 0x7ff00000) == 0x7ff00000) out[0] = 0;
58531914882SAlex Richardson     else out[0] = 1;
58631914882SAlex Richardson     return NULL;
58731914882SAlex Richardson }
58831914882SAlex Richardson 
test_isfinitef(uint32 * x,uint32 * out)58931914882SAlex Richardson char *test_isfinitef(uint32 *x, uint32 *out)
59031914882SAlex Richardson {
59131914882SAlex Richardson     /* Being finite means that the exponent is not 0xff */
59231914882SAlex Richardson     if ((x[0] & 0x7f800000) == 0x7f800000) out[0] = 0;
59331914882SAlex Richardson     else out[0] = 1;
59431914882SAlex Richardson     return NULL;
59531914882SAlex Richardson }
59631914882SAlex Richardson 
test_isinff(uint32 * x,uint32 * out)59731914882SAlex Richardson char *test_isinff(uint32 *x, uint32 *out)
59831914882SAlex Richardson {
59931914882SAlex Richardson     /* Being infinite means that our bottom 30 bits equate to 0x7f800000 */
60031914882SAlex Richardson     if ((x[0] & 0x7fffffff) == 0x7f800000) out[0] = 1;
60131914882SAlex Richardson     else out[0] = 0;
60231914882SAlex Richardson     return NULL;
60331914882SAlex Richardson }
60431914882SAlex Richardson 
test_isinf(uint32 * x,uint32 * out)60531914882SAlex Richardson char *test_isinf(uint32 *x, uint32 *out)
60631914882SAlex Richardson {
60731914882SAlex Richardson     int xhigh = x[0];
60831914882SAlex Richardson     int xlow = x[1];
60931914882SAlex Richardson     /* Being infinite means that our fraction is zero and exponent is 0x7ff */
61031914882SAlex Richardson     if (((xhigh & 0x7fffffff) == 0x7ff00000) && (xlow == 0)) out[0] = 1;
61131914882SAlex Richardson     else out[0] = 0;
61231914882SAlex Richardson     return NULL;
61331914882SAlex Richardson }
61431914882SAlex Richardson 
test_isnanf(uint32 * x,uint32 * out)61531914882SAlex Richardson char *test_isnanf(uint32 *x, uint32 *out)
61631914882SAlex Richardson {
61731914882SAlex Richardson     /* Being NaN means that our exponent is 0xff and non-0 fraction */
61831914882SAlex Richardson     int exponent = x[0] & 0x7f800000;
61931914882SAlex Richardson     int fraction = x[0] & 0x007fffff;
62031914882SAlex Richardson     if ((exponent == 0x7f800000) && (fraction != 0)) out[0] = 1;
62131914882SAlex Richardson     else out[0] = 0;
62231914882SAlex Richardson     return NULL;
62331914882SAlex Richardson }
62431914882SAlex Richardson 
test_isnan(uint32 * x,uint32 * out)62531914882SAlex Richardson char *test_isnan(uint32 *x, uint32 *out)
62631914882SAlex Richardson {
62731914882SAlex Richardson     /* Being NaN means that our exponent is 0x7ff and non-0 fraction */
62831914882SAlex Richardson     int exponent = x[0] & 0x7ff00000;
62931914882SAlex Richardson     int fractionhigh = x[0] & 0x000fffff;
63031914882SAlex Richardson     if ((exponent == 0x7ff00000) && ((fractionhigh != 0) || x[1] != 0))
63131914882SAlex Richardson         out[0] = 1;
63231914882SAlex Richardson     else out[0] = 0;
63331914882SAlex Richardson     return NULL;
63431914882SAlex Richardson }
63531914882SAlex Richardson 
test_isnormalf(uint32 * x,uint32 * out)63631914882SAlex Richardson char *test_isnormalf(uint32 *x, uint32 *out)
63731914882SAlex Richardson {
63831914882SAlex Richardson     /* Being normal means exponent is not 0 and is not 0xff */
63931914882SAlex Richardson     int exponent = x[0] & 0x7f800000;
64031914882SAlex Richardson     if (exponent == 0x7f800000) out[0] = 0;
64131914882SAlex Richardson     else if (exponent == 0) out[0] = 0;
64231914882SAlex Richardson     else out[0] = 1;
64331914882SAlex Richardson     return NULL;
64431914882SAlex Richardson }
64531914882SAlex Richardson 
test_isnormal(uint32 * x,uint32 * out)64631914882SAlex Richardson char *test_isnormal(uint32 *x, uint32 *out)
64731914882SAlex Richardson {
64831914882SAlex Richardson     /* Being normal means exponent is not 0 and is not 0x7ff */
64931914882SAlex Richardson     int exponent = x[0] & 0x7ff00000;
65031914882SAlex Richardson     if (exponent == 0x7ff00000) out[0] = 0;
65131914882SAlex Richardson     else if (exponent == 0) out[0] = 0;
65231914882SAlex Richardson     else out[0] = 1;
65331914882SAlex Richardson     return NULL;
65431914882SAlex Richardson }
65531914882SAlex Richardson 
test_signbitf(uint32 * x,uint32 * out)65631914882SAlex Richardson char *test_signbitf(uint32 *x, uint32 *out)
65731914882SAlex Richardson {
65831914882SAlex Richardson     /* Sign bit is bit 31 */
65931914882SAlex Richardson     out[0] = (x[0] >> 31) & 1;
66031914882SAlex Richardson     return NULL;
66131914882SAlex Richardson }
66231914882SAlex Richardson 
test_signbit(uint32 * x,uint32 * out)66331914882SAlex Richardson char *test_signbit(uint32 *x, uint32 *out)
66431914882SAlex Richardson {
66531914882SAlex Richardson     /* Sign bit is bit 31 */
66631914882SAlex Richardson     out[0] = (x[0] >> 31) & 1;
66731914882SAlex Richardson     return NULL;
66831914882SAlex Richardson }
66931914882SAlex Richardson 
test_fpclassify(uint32 * x,uint32 * out)67031914882SAlex Richardson char *test_fpclassify(uint32 *x, uint32 *out)
67131914882SAlex Richardson {
67231914882SAlex Richardson     int exponent = (x[0] & 0x7ff00000) >> 20;
67331914882SAlex Richardson     int fraction = (x[0] & 0x000fffff) | x[1];
67431914882SAlex Richardson 
67531914882SAlex Richardson     if ((exponent == 0x00) && (fraction == 0)) out[0] = 0;
67631914882SAlex Richardson     else if ((exponent == 0x00) && (fraction != 0)) out[0] = 4;
67731914882SAlex Richardson     else if ((exponent == 0x7ff) && (fraction == 0)) out[0] = 3;
67831914882SAlex Richardson     else if ((exponent == 0x7ff) && (fraction != 0)) out[0] = 7;
67931914882SAlex Richardson     else out[0] = 5;
68031914882SAlex Richardson     return NULL;
68131914882SAlex Richardson }
68231914882SAlex Richardson 
test_fpclassifyf(uint32 * x,uint32 * out)68331914882SAlex Richardson char *test_fpclassifyf(uint32 *x, uint32 *out)
68431914882SAlex Richardson {
68531914882SAlex Richardson     int exponent = (x[0] & 0x7f800000) >> 23;
68631914882SAlex Richardson     int fraction = x[0] & 0x007fffff;
68731914882SAlex Richardson 
68831914882SAlex Richardson     if ((exponent == 0x000) && (fraction == 0)) out[0] = 0;
68931914882SAlex Richardson     else if ((exponent == 0x000) && (fraction != 0)) out[0] = 4;
69031914882SAlex Richardson     else if ((exponent == 0xff) && (fraction == 0)) out[0] = 3;
69131914882SAlex Richardson     else if ((exponent == 0xff) && (fraction != 0)) out[0] = 7;
69231914882SAlex Richardson     else out[0] = 5;
69331914882SAlex Richardson     return NULL;
69431914882SAlex Richardson }
69531914882SAlex Richardson 
69631914882SAlex Richardson /*
69731914882SAlex Richardson  * Internal function that compares doubles in x & y and returns -3, -2, -1, 0,
69831914882SAlex Richardson  * 1 if they compare to be signaling, unordered, less than, equal or greater
69931914882SAlex Richardson  * than.
70031914882SAlex Richardson  */
fpcmp4(uint32 * x,uint32 * y)70131914882SAlex Richardson static int fpcmp4(uint32 *x, uint32 *y)
70231914882SAlex Richardson {
70331914882SAlex Richardson     int result = 0;
70431914882SAlex Richardson 
70531914882SAlex Richardson     /*
70631914882SAlex Richardson      * Sort out whether results are ordered or not to begin with
70731914882SAlex Richardson      * NaNs have exponent 0x7ff, and non-zero fraction. Signaling NaNs take
70831914882SAlex Richardson      * higher priority than quiet ones.
70931914882SAlex Richardson      */
71031914882SAlex Richardson     if ((x[0] & 0x7fffffff) >= 0x7ff80000) result = -2;
71131914882SAlex Richardson     else if ((x[0] & 0x7fffffff) > 0x7ff00000) result = -3;
71231914882SAlex Richardson     else if (((x[0] & 0x7fffffff) == 0x7ff00000) && (x[1] != 0)) result = -3;
71331914882SAlex Richardson     if ((y[0] & 0x7fffffff) >= 0x7ff80000 && result != -3) result = -2;
71431914882SAlex Richardson     else if ((y[0] & 0x7fffffff) > 0x7ff00000) result = -3;
71531914882SAlex Richardson     else if (((y[0] & 0x7fffffff) == 0x7ff00000) && (y[1] != 0)) result = -3;
71631914882SAlex Richardson     if (result != 0) return result;
71731914882SAlex Richardson 
71831914882SAlex Richardson     /*
71931914882SAlex Richardson      * The two forms of zero are equal
72031914882SAlex Richardson      */
72131914882SAlex Richardson     if (((x[0] & 0x7fffffff) == 0) && x[1] == 0 &&
72231914882SAlex Richardson         ((y[0] & 0x7fffffff) == 0) && y[1] == 0)
72331914882SAlex Richardson         return 0;
72431914882SAlex Richardson 
72531914882SAlex Richardson     /*
72631914882SAlex Richardson      * If x and y have different signs we can tell that they're not equal
72731914882SAlex Richardson      * If x is +ve we have x > y return 1 - otherwise y is +ve return -1
72831914882SAlex Richardson      */
72931914882SAlex Richardson     if ((x[0] >> 31) != (y[0] >> 31))
73031914882SAlex Richardson         return ((x[0] >> 31) == 0) - ((y[0] >> 31) == 0);
73131914882SAlex Richardson 
73231914882SAlex Richardson     /*
73331914882SAlex Richardson      * Now we have both signs the same, let's do an initial compare of the
73431914882SAlex Richardson      * values.
73531914882SAlex Richardson      *
73631914882SAlex Richardson      * Whoever designed IEEE754's floating point formats is very clever and
73731914882SAlex Richardson      * earns my undying admiration.  Once you remove the sign-bit, the
73831914882SAlex Richardson      * floating point numbers can be ordered using the standard <, ==, >
73931914882SAlex Richardson      * operators will treating the fp-numbers as integers with that bit-
74031914882SAlex Richardson      * pattern.
74131914882SAlex Richardson      */
74231914882SAlex Richardson     if ((x[0] & 0x7fffffff) < (y[0] & 0x7fffffff)) result = -1;
74331914882SAlex Richardson     else if ((x[0] & 0x7fffffff) > (y[0] & 0x7fffffff)) result = 1;
74431914882SAlex Richardson     else if (x[1] < y[1]) result = -1;
74531914882SAlex Richardson     else if (x[1] > y[1]) result = 1;
74631914882SAlex Richardson     else result = 0;
74731914882SAlex Richardson 
74831914882SAlex Richardson     /*
74931914882SAlex Richardson      * Now we return the result - is x is positive (and therefore so is y) we
75031914882SAlex Richardson      * return the plain result - otherwise we negate it and return.
75131914882SAlex Richardson      */
75231914882SAlex Richardson     if ((x[0] >> 31) == 0) return result;
75331914882SAlex Richardson     else return -result;
75431914882SAlex Richardson }
75531914882SAlex Richardson 
75631914882SAlex Richardson /*
75731914882SAlex Richardson  * Internal function that compares floats in x & y and returns -3, -2, -1, 0,
75831914882SAlex Richardson  * 1 if they compare to be signaling, unordered, less than, equal or greater
75931914882SAlex Richardson  * than.
76031914882SAlex Richardson  */
fpcmp4f(uint32 * x,uint32 * y)76131914882SAlex Richardson static int fpcmp4f(uint32 *x, uint32 *y)
76231914882SAlex Richardson {
76331914882SAlex Richardson     int result = 0;
76431914882SAlex Richardson 
76531914882SAlex Richardson     /*
76631914882SAlex Richardson      * Sort out whether results are ordered or not to begin with
76731914882SAlex Richardson      * NaNs have exponent 0xff, and non-zero fraction - we have to handle all
76831914882SAlex Richardson      * signaling cases over the quiet ones
76931914882SAlex Richardson      */
77031914882SAlex Richardson     if ((x[0] & 0x7fffffff) >= 0x7fc00000) result = -2;
77131914882SAlex Richardson     else if ((x[0] & 0x7fffffff) > 0x7f800000) result = -3;
77231914882SAlex Richardson     if ((y[0] & 0x7fffffff) >= 0x7fc00000 && result != -3) result = -2;
77331914882SAlex Richardson     else if ((y[0] & 0x7fffffff) > 0x7f800000) result = -3;
77431914882SAlex Richardson     if (result != 0) return result;
77531914882SAlex Richardson 
77631914882SAlex Richardson     /*
77731914882SAlex Richardson      * The two forms of zero are equal
77831914882SAlex Richardson      */
77931914882SAlex Richardson     if (((x[0] & 0x7fffffff) == 0) && ((y[0] & 0x7fffffff) == 0))
78031914882SAlex Richardson         return 0;
78131914882SAlex Richardson 
78231914882SAlex Richardson     /*
78331914882SAlex Richardson      * If x and y have different signs we can tell that they're not equal
78431914882SAlex Richardson      * If x is +ve we have x > y return 1 - otherwise y is +ve return -1
78531914882SAlex Richardson      */
78631914882SAlex Richardson     if ((x[0] >> 31) != (y[0] >> 31))
78731914882SAlex Richardson         return ((x[0] >> 31) == 0) - ((y[0] >> 31) == 0);
78831914882SAlex Richardson 
78931914882SAlex Richardson     /*
79031914882SAlex Richardson      * Now we have both signs the same, let's do an initial compare of the
79131914882SAlex Richardson      * values.
79231914882SAlex Richardson      *
79331914882SAlex Richardson      * Whoever designed IEEE754's floating point formats is very clever and
79431914882SAlex Richardson      * earns my undying admiration.  Once you remove the sign-bit, the
79531914882SAlex Richardson      * floating point numbers can be ordered using the standard <, ==, >
79631914882SAlex Richardson      * operators will treating the fp-numbers as integers with that bit-
79731914882SAlex Richardson      * pattern.
79831914882SAlex Richardson      */
79931914882SAlex Richardson     if ((x[0] & 0x7fffffff) < (y[0] & 0x7fffffff)) result = -1;
80031914882SAlex Richardson     else if ((x[0] & 0x7fffffff) > (y[0] & 0x7fffffff)) result = 1;
80131914882SAlex Richardson     else result = 0;
80231914882SAlex Richardson 
80331914882SAlex Richardson     /*
80431914882SAlex Richardson      * Now we return the result - is x is positive (and therefore so is y) we
80531914882SAlex Richardson      * return the plain result - otherwise we negate it and return.
80631914882SAlex Richardson      */
80731914882SAlex Richardson     if ((x[0] >> 31) == 0) return result;
80831914882SAlex Richardson     else return -result;
80931914882SAlex Richardson }
81031914882SAlex Richardson 
test_isgreater(uint32 * x,uint32 * y,uint32 * out)81131914882SAlex Richardson char *test_isgreater(uint32 *x, uint32 *y, uint32 *out)
81231914882SAlex Richardson {
81331914882SAlex Richardson     int result = fpcmp4(x, y);
81431914882SAlex Richardson     *out = (result == 1);
81531914882SAlex Richardson     return result == -3 ? "i" : NULL;
81631914882SAlex Richardson }
81731914882SAlex Richardson 
test_isgreaterequal(uint32 * x,uint32 * y,uint32 * out)81831914882SAlex Richardson char *test_isgreaterequal(uint32 *x, uint32 *y, uint32 *out)
81931914882SAlex Richardson {
82031914882SAlex Richardson     int result = fpcmp4(x, y);
82131914882SAlex Richardson     *out = (result >= 0);
82231914882SAlex Richardson     return result == -3 ? "i" : NULL;
82331914882SAlex Richardson }
82431914882SAlex Richardson 
test_isless(uint32 * x,uint32 * y,uint32 * out)82531914882SAlex Richardson char *test_isless(uint32 *x, uint32 *y, uint32 *out)
82631914882SAlex Richardson {
82731914882SAlex Richardson     int result = fpcmp4(x, y);
82831914882SAlex Richardson     *out = (result == -1);
82931914882SAlex Richardson     return result == -3 ? "i" : NULL;
83031914882SAlex Richardson }
83131914882SAlex Richardson 
test_islessequal(uint32 * x,uint32 * y,uint32 * out)83231914882SAlex Richardson char *test_islessequal(uint32 *x, uint32 *y, uint32 *out)
83331914882SAlex Richardson {
83431914882SAlex Richardson     int result = fpcmp4(x, y);
83531914882SAlex Richardson     *out = (result == -1) || (result == 0);
83631914882SAlex Richardson     return result == -3 ? "i" : NULL;
83731914882SAlex Richardson }
83831914882SAlex Richardson 
test_islessgreater(uint32 * x,uint32 * y,uint32 * out)83931914882SAlex Richardson char *test_islessgreater(uint32 *x, uint32 *y, uint32 *out)
84031914882SAlex Richardson {
84131914882SAlex Richardson     int result = fpcmp4(x, y);
84231914882SAlex Richardson     *out = (result == -1) || (result == 1);
84331914882SAlex Richardson     return result == -3 ? "i" : NULL;
84431914882SAlex Richardson }
84531914882SAlex Richardson 
test_isunordered(uint32 * x,uint32 * y,uint32 * out)84631914882SAlex Richardson char *test_isunordered(uint32 *x, uint32 *y, uint32 *out)
84731914882SAlex Richardson {
84831914882SAlex Richardson     int normal = 0;
84931914882SAlex Richardson     int result = fpcmp4(x, y);
85031914882SAlex Richardson 
85131914882SAlex Richardson     test_isnormal(x, out);
85231914882SAlex Richardson     normal |= *out;
85331914882SAlex Richardson     test_isnormal(y, out);
85431914882SAlex Richardson     normal |= *out;
85531914882SAlex Richardson     *out = (result == -2) || (result == -3);
85631914882SAlex Richardson     return result == -3 ? "i" : NULL;
85731914882SAlex Richardson }
85831914882SAlex Richardson 
test_isgreaterf(uint32 * x,uint32 * y,uint32 * out)85931914882SAlex Richardson char *test_isgreaterf(uint32 *x, uint32 *y, uint32 *out)
86031914882SAlex Richardson {
86131914882SAlex Richardson     int result = fpcmp4f(x, y);
86231914882SAlex Richardson     *out = (result == 1);
86331914882SAlex Richardson     return result == -3 ? "i" : NULL;
86431914882SAlex Richardson }
86531914882SAlex Richardson 
test_isgreaterequalf(uint32 * x,uint32 * y,uint32 * out)86631914882SAlex Richardson char *test_isgreaterequalf(uint32 *x, uint32 *y, uint32 *out)
86731914882SAlex Richardson {
86831914882SAlex Richardson     int result = fpcmp4f(x, y);
86931914882SAlex Richardson     *out = (result >= 0);
87031914882SAlex Richardson     return result == -3 ? "i" : NULL;
87131914882SAlex Richardson }
87231914882SAlex Richardson 
test_islessf(uint32 * x,uint32 * y,uint32 * out)87331914882SAlex Richardson char *test_islessf(uint32 *x, uint32 *y, uint32 *out)
87431914882SAlex Richardson {
87531914882SAlex Richardson     int result = fpcmp4f(x, y);
87631914882SAlex Richardson     *out = (result == -1);
87731914882SAlex Richardson     return result == -3 ? "i" : NULL;
87831914882SAlex Richardson }
87931914882SAlex Richardson 
test_islessequalf(uint32 * x,uint32 * y,uint32 * out)88031914882SAlex Richardson char *test_islessequalf(uint32 *x, uint32 *y, uint32 *out)
88131914882SAlex Richardson {
88231914882SAlex Richardson     int result = fpcmp4f(x, y);
88331914882SAlex Richardson     *out = (result == -1) || (result == 0);
88431914882SAlex Richardson     return result == -3 ? "i" : NULL;
88531914882SAlex Richardson }
88631914882SAlex Richardson 
test_islessgreaterf(uint32 * x,uint32 * y,uint32 * out)88731914882SAlex Richardson char *test_islessgreaterf(uint32 *x, uint32 *y, uint32 *out)
88831914882SAlex Richardson {
88931914882SAlex Richardson     int result = fpcmp4f(x, y);
89031914882SAlex Richardson     *out = (result == -1) || (result == 1);
89131914882SAlex Richardson     return result == -3 ? "i" : NULL;
89231914882SAlex Richardson }
89331914882SAlex Richardson 
test_isunorderedf(uint32 * x,uint32 * y,uint32 * out)89431914882SAlex Richardson char *test_isunorderedf(uint32 *x, uint32 *y, uint32 *out)
89531914882SAlex Richardson {
89631914882SAlex Richardson     int normal = 0;
89731914882SAlex Richardson     int result = fpcmp4f(x, y);
89831914882SAlex Richardson 
89931914882SAlex Richardson     test_isnormalf(x, out);
90031914882SAlex Richardson     normal |= *out;
90131914882SAlex Richardson     test_isnormalf(y, out);
90231914882SAlex Richardson     normal |= *out;
90331914882SAlex Richardson     *out = (result == -2) || (result == -3);
90431914882SAlex Richardson     return result == -3 ? "i" : NULL;
90531914882SAlex Richardson }
906