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