diff options
Diffstat (limited to 'math/test/rtest/semi.c')
| -rw-r--r-- | math/test/rtest/semi.c | 905 |
1 files changed, 905 insertions, 0 deletions
diff --git a/math/test/rtest/semi.c b/math/test/rtest/semi.c new file mode 100644 index 000000000000..c9f0daf76508 --- /dev/null +++ b/math/test/rtest/semi.c @@ -0,0 +1,905 @@ +/* + * semi.c: test implementations of mathlib seminumerical functions + * + * Copyright (c) 1999-2019, Arm Limited. + * SPDX-License-Identifier: MIT + */ + +#include <stdio.h> +#include "semi.h" + +static void test_rint(uint32 *in, uint32 *out, + int isfloor, int isceil) { + int sign = in[0] & 0x80000000; + int roundup = (isfloor && sign) || (isceil && !sign); + uint32 xh, xl, roundword; + int ex = (in[0] >> 20) & 0x7FF; /* exponent */ + int i; + + if ((ex > 0x3ff + 52 - 1) || /* things this big can't be fractional */ + ((in[0] & 0x7FFFFFFF) == 0 && in[1] == 0)) { /* zero */ + /* NaN, Inf, a large integer, or zero: just return the input */ + out[0] = in[0]; + out[1] = in[1]; + return; + } + + /* + * Special case: ex < 0x3ff, ie our number is in (0,1). Return + * 1 or 0 according to roundup. + */ + if (ex < 0x3ff) { + out[0] = sign | (roundup ? 0x3FF00000 : 0); + out[1] = 0; + return; + } + + /* + * We're not short of time here, so we'll do this the hideously + * inefficient way. Shift bit by bit so that the units place is + * somewhere predictable, round, and shift back again. + */ + xh = in[0]; + xl = in[1]; + roundword = 0; + for (i = ex; i < 0x3ff + 52; i++) { + if (roundword & 1) + roundword |= 2; /* preserve sticky bit */ + roundword = (roundword >> 1) | ((xl & 1) << 31); + xl = (xl >> 1) | ((xh & 1) << 31); + xh = xh >> 1; + } + if (roundword && roundup) { + xl++; + xh += (xl==0); + } + for (i = ex; i < 0x3ff + 52; i++) { + xh = (xh << 1) | ((xl >> 31) & 1); + xl = (xl & 0x7FFFFFFF) << 1; + } + out[0] = xh; + out[1] = xl; +} + +char *test_ceil(uint32 *in, uint32 *out) { + test_rint(in, out, 0, 1); + return NULL; +} + +char *test_floor(uint32 *in, uint32 *out) { + test_rint(in, out, 1, 0); + return NULL; +} + +static void test_rintf(uint32 *in, uint32 *out, + int isfloor, int isceil) { + int sign = *in & 0x80000000; + int roundup = (isfloor && sign) || (isceil && !sign); + uint32 x, roundword; + int ex = (*in >> 23) & 0xFF; /* exponent */ + int i; + + if ((ex > 0x7f + 23 - 1) || /* things this big can't be fractional */ + (*in & 0x7FFFFFFF) == 0) { /* zero */ + /* NaN, Inf, a large integer, or zero: just return the input */ + *out = *in; + return; + } + + /* + * Special case: ex < 0x7f, ie our number is in (0,1). Return + * 1 or 0 according to roundup. + */ + if (ex < 0x7f) { + *out = sign | (roundup ? 0x3F800000 : 0); + return; + } + + /* + * We're not short of time here, so we'll do this the hideously + * inefficient way. Shift bit by bit so that the units place is + * somewhere predictable, round, and shift back again. + */ + x = *in; + roundword = 0; + for (i = ex; i < 0x7F + 23; i++) { + if (roundword & 1) + roundword |= 2; /* preserve sticky bit */ + roundword = (roundword >> 1) | ((x & 1) << 31); + x = x >> 1; + } + if (roundword && roundup) { + x++; + } + for (i = ex; i < 0x7F + 23; i++) { + x = x << 1; + } + *out = x; +} + +char *test_ceilf(uint32 *in, uint32 *out) { + test_rintf(in, out, 0, 1); + return NULL; +} + +char *test_floorf(uint32 *in, uint32 *out) { + test_rintf(in, out, 1, 0); + return NULL; +} + +char *test_fmod(uint32 *a, uint32 *b, uint32 *out) { + int sign; + int32 aex, bex; + uint32 am[2], bm[2]; + + if (((a[0] & 0x7FFFFFFF) << 1) + !!a[1] > 0xFFE00000 || + ((b[0] & 0x7FFFFFFF) << 1) + !!b[1] > 0xFFE00000) { + /* a or b is NaN: return QNaN, optionally with IVO */ + uint32 an, bn; + out[0] = 0x7ff80000; + out[1] = 1; + an = ((a[0] & 0x7FFFFFFF) << 1) + !!a[1]; + bn = ((b[0] & 0x7FFFFFFF) << 1) + !!b[1]; + if ((an > 0xFFE00000 && an < 0xFFF00000) || + (bn > 0xFFE00000 && bn < 0xFFF00000)) + return "i"; /* at least one SNaN: IVO */ + else + return NULL; /* no SNaNs, but at least 1 QNaN */ + } + if ((b[0] & 0x7FFFFFFF) == 0 && b[1] == 0) { /* b==0: EDOM */ + out[0] = 0x7ff80000; + out[1] = 1; + return "EDOM status=i"; + } + if ((a[0] & 0x7FF00000) == 0x7FF00000) { /* a==Inf: EDOM */ + out[0] = 0x7ff80000; + out[1] = 1; + return "EDOM status=i"; + } + if ((b[0] & 0x7FF00000) == 0x7FF00000) { /* b==Inf: return a */ + out[0] = a[0]; + out[1] = a[1]; + return NULL; + } + if ((a[0] & 0x7FFFFFFF) == 0 && a[1] == 0) { /* a==0: return a */ + out[0] = a[0]; + out[1] = a[1]; + return NULL; + } + + /* + * OK. That's the special cases cleared out of the way. Now we + * have finite (though not necessarily normal) a and b. + */ + sign = a[0] & 0x80000000; /* we discard sign of b */ + test_frexp(a, am, (uint32 *)&aex); + test_frexp(b, bm, (uint32 *)&bex); + am[0] &= 0xFFFFF, am[0] |= 0x100000; + bm[0] &= 0xFFFFF, bm[0] |= 0x100000; + + while (aex >= bex) { + if (am[0] > bm[0] || (am[0] == bm[0] && am[1] >= bm[1])) { + am[1] -= bm[1]; + am[0] = am[0] - bm[0] - (am[1] > ~bm[1]); + } + if (aex > bex) { + am[0] = (am[0] << 1) | ((am[1] & 0x80000000) >> 31); + am[1] <<= 1; + aex--; + } else + break; + } + + /* + * Renormalise final result; this can be cunningly done by + * passing a denormal to ldexp. + */ + aex += 0x3fd; + am[0] |= sign; + test_ldexp(am, (uint32 *)&aex, out); + + return NULL; /* FIXME */ +} + +char *test_fmodf(uint32 *a, uint32 *b, uint32 *out) { + int sign; + int32 aex, bex; + uint32 am, bm; + + if ((*a & 0x7FFFFFFF) > 0x7F800000 || + (*b & 0x7FFFFFFF) > 0x7F800000) { + /* a or b is NaN: return QNaN, optionally with IVO */ + uint32 an, bn; + *out = 0x7fc00001; + an = *a & 0x7FFFFFFF; + bn = *b & 0x7FFFFFFF; + if ((an > 0x7f800000 && an < 0x7fc00000) || + (bn > 0x7f800000 && bn < 0x7fc00000)) + return "i"; /* at least one SNaN: IVO */ + else + return NULL; /* no SNaNs, but at least 1 QNaN */ + } + if ((*b & 0x7FFFFFFF) == 0) { /* b==0: EDOM */ + *out = 0x7fc00001; + return "EDOM status=i"; + } + if ((*a & 0x7F800000) == 0x7F800000) { /* a==Inf: EDOM */ + *out = 0x7fc00001; + return "EDOM status=i"; + } + if ((*b & 0x7F800000) == 0x7F800000) { /* b==Inf: return a */ + *out = *a; + return NULL; + } + if ((*a & 0x7FFFFFFF) == 0) { /* a==0: return a */ + *out = *a; + return NULL; + } + + /* + * OK. That's the special cases cleared out of the way. Now we + * have finite (though not necessarily normal) a and b. + */ + sign = a[0] & 0x80000000; /* we discard sign of b */ + test_frexpf(a, &am, (uint32 *)&aex); + test_frexpf(b, &bm, (uint32 *)&bex); + am &= 0x7FFFFF, am |= 0x800000; + bm &= 0x7FFFFF, bm |= 0x800000; + + while (aex >= bex) { + if (am >= bm) { + am -= bm; + } + if (aex > bex) { + am <<= 1; + aex--; + } else + break; + } + + /* + * Renormalise final result; this can be cunningly done by + * passing a denormal to ldexp. + */ + aex += 0x7d; + am |= sign; + test_ldexpf(&am, (uint32 *)&aex, out); + + return NULL; /* FIXME */ +} + +char *test_ldexp(uint32 *x, uint32 *np, uint32 *out) { + int n = *np; + int32 n2; + uint32 y[2]; + int ex = (x[0] >> 20) & 0x7FF; /* exponent */ + int sign = x[0] & 0x80000000; + + if (ex == 0x7FF) { /* inf/NaN; just return x */ + out[0] = x[0]; + out[1] = x[1]; + return NULL; + } + if ((x[0] & 0x7FFFFFFF) == 0 && x[1] == 0) { /* zero: return x */ + out[0] = x[0]; + out[1] = x[1]; + return NULL; + } + + test_frexp(x, y, (uint32 *)&n2); + ex = n + n2; + if (ex > 0x400) { /* overflow */ + out[0] = sign | 0x7FF00000; + out[1] = 0; + return "overflow"; + } + /* + * Underflow. 2^-1074 is 00000000.00000001; so if ex == -1074 + * then we have something [2^-1075,2^-1074). Under round-to- + * nearest-even, this whole interval rounds up to 2^-1074, + * except for the bottom endpoint which rounds to even and is + * an underflow condition. + * + * So, ex < -1074 is definite underflow, and ex == -1074 is + * underflow iff all mantissa bits are zero. + */ + if (ex < -1074 || (ex == -1074 && (y[0] & 0xFFFFF) == 0 && y[1] == 0)) { + out[0] = sign; /* underflow: correctly signed zero */ + out[1] = 0; + return "underflow"; + } + + /* + * No overflow or underflow; should be nice and simple, unless + * we have to denormalise and round the result. + */ + if (ex < -1021) { /* denormalise and round */ + uint32 roundword; + y[0] &= 0x000FFFFF; + y[0] |= 0x00100000; /* set leading bit */ + roundword = 0; + while (ex < -1021) { + if (roundword & 1) + roundword |= 2; /* preserve sticky bit */ + roundword = (roundword >> 1) | ((y[1] & 1) << 31); + y[1] = (y[1] >> 1) | ((y[0] & 1) << 31); + y[0] = y[0] >> 1; + ex++; + } + if (roundword > 0x80000000 || /* round up */ + (roundword == 0x80000000 && (y[1] & 1))) { /* round up to even */ + y[1]++; + y[0] += (y[1] == 0); + } + out[0] = sign | y[0]; + out[1] = y[1]; + /* Proper ERANGE underflow was handled earlier, but we still + * expect an IEEE Underflow exception if this partially + * underflowed result is not exact. */ + if (roundword) + return "u"; + return NULL; /* underflow was handled earlier */ + } else { + out[0] = y[0] + (ex << 20); + out[1] = y[1]; + return NULL; + } +} + +char *test_ldexpf(uint32 *x, uint32 *np, uint32 *out) { + int n = *np; + int32 n2; + uint32 y; + int ex = (*x >> 23) & 0xFF; /* exponent */ + int sign = *x & 0x80000000; + + if (ex == 0xFF) { /* inf/NaN; just return x */ + *out = *x; + return NULL; + } + if ((*x & 0x7FFFFFFF) == 0) { /* zero: return x */ + *out = *x; + return NULL; + } + + test_frexpf(x, &y, (uint32 *)&n2); + ex = n + n2; + if (ex > 0x80) { /* overflow */ + *out = sign | 0x7F800000; + return "overflow"; + } + /* + * Underflow. 2^-149 is 00000001; so if ex == -149 then we have + * something [2^-150,2^-149). Under round-to- nearest-even, + * this whole interval rounds up to 2^-149, except for the + * bottom endpoint which rounds to even and is an underflow + * condition. + * + * So, ex < -149 is definite underflow, and ex == -149 is + * underflow iff all mantissa bits are zero. + */ + if (ex < -149 || (ex == -149 && (y & 0x7FFFFF) == 0)) { + *out = sign; /* underflow: correctly signed zero */ + return "underflow"; + } + + /* + * No overflow or underflow; should be nice and simple, unless + * we have to denormalise and round the result. + */ + if (ex < -125) { /* denormalise and round */ + uint32 roundword; + y &= 0x007FFFFF; + y |= 0x00800000; /* set leading bit */ + roundword = 0; + while (ex < -125) { + if (roundword & 1) + roundword |= 2; /* preserve sticky bit */ + roundword = (roundword >> 1) | ((y & 1) << 31); + y = y >> 1; + ex++; + } + if (roundword > 0x80000000 || /* round up */ + (roundword == 0x80000000 && (y & 1))) { /* round up to even */ + y++; + } + *out = sign | y; + /* Proper ERANGE underflow was handled earlier, but we still + * expect an IEEE Underflow exception if this partially + * underflowed result is not exact. */ + if (roundword) + return "u"; + return NULL; /* underflow was handled earlier */ + } else { + *out = y + (ex << 23); + return NULL; + } +} + +char *test_frexp(uint32 *x, uint32 *out, uint32 *nout) { + int ex = (x[0] >> 20) & 0x7FF; /* exponent */ + if (ex == 0x7FF) { /* inf/NaN; return x/0 */ + out[0] = x[0]; + out[1] = x[1]; + nout[0] = 0; + return NULL; + } + if (ex == 0) { /* denormals/zeros */ + int sign; + uint32 xh, xl; + if ((x[0] & 0x7FFFFFFF) == 0 && x[1] == 0) { + /* zero: return x/0 */ + out[0] = x[0]; + out[1] = x[1]; + nout[0] = 0; + return NULL; + } + sign = x[0] & 0x80000000; + xh = x[0] & 0x7FFFFFFF; + xl = x[1]; + ex = 1; + while (!(xh & 0x100000)) { + ex--; + xh = (xh << 1) | ((xl >> 31) & 1); + xl = (xl & 0x7FFFFFFF) << 1; + } + out[0] = sign | 0x3FE00000 | (xh & 0xFFFFF); + out[1] = xl; + nout[0] = ex - 0x3FE; + return NULL; + } + out[0] = 0x3FE00000 | (x[0] & 0x800FFFFF); + out[1] = x[1]; + nout[0] = ex - 0x3FE; + return NULL; /* ordinary number; no error */ +} + +char *test_frexpf(uint32 *x, uint32 *out, uint32 *nout) { + int ex = (*x >> 23) & 0xFF; /* exponent */ + if (ex == 0xFF) { /* inf/NaN; return x/0 */ + *out = *x; + nout[0] = 0; + return NULL; + } + if (ex == 0) { /* denormals/zeros */ + int sign; + uint32 xv; + if ((*x & 0x7FFFFFFF) == 0) { + /* zero: return x/0 */ + *out = *x; + nout[0] = 0; + return NULL; + } + sign = *x & 0x80000000; + xv = *x & 0x7FFFFFFF; + ex = 1; + while (!(xv & 0x800000)) { + ex--; + xv = xv << 1; + } + *out = sign | 0x3F000000 | (xv & 0x7FFFFF); + nout[0] = ex - 0x7E; + return NULL; + } + *out = 0x3F000000 | (*x & 0x807FFFFF); + nout[0] = ex - 0x7E; + return NULL; /* ordinary number; no error */ +} + +char *test_modf(uint32 *x, uint32 *fout, uint32 *iout) { + int ex = (x[0] >> 20) & 0x7FF; /* exponent */ + int sign = x[0] & 0x80000000; + uint32 fh, fl; + + if (((x[0] & 0x7FFFFFFF) | (!!x[1])) > 0x7FF00000) { + /* + * NaN input: return the same in _both_ outputs. + */ + fout[0] = iout[0] = x[0]; + fout[1] = iout[1] = x[1]; + return NULL; + } + + test_rint(x, iout, 0, 0); + fh = x[0] - iout[0]; + fl = x[1] - iout[1]; + if (!fh && !fl) { /* no fraction part */ + fout[0] = sign; + fout[1] = 0; + return NULL; + } + if (!(iout[0] & 0x7FFFFFFF) && !iout[1]) { /* no integer part */ + fout[0] = x[0]; + fout[1] = x[1]; + return NULL; + } + while (!(fh & 0x100000)) { + ex--; + fh = (fh << 1) | ((fl >> 31) & 1); + fl = (fl & 0x7FFFFFFF) << 1; + } + fout[0] = sign | (ex << 20) | (fh & 0xFFFFF); + fout[1] = fl; + return NULL; +} + +char *test_modff(uint32 *x, uint32 *fout, uint32 *iout) { + int ex = (*x >> 23) & 0xFF; /* exponent */ + int sign = *x & 0x80000000; + uint32 f; + + if ((*x & 0x7FFFFFFF) > 0x7F800000) { + /* + * NaN input: return the same in _both_ outputs. + */ + *fout = *iout = *x; + return NULL; + } + + test_rintf(x, iout, 0, 0); + f = *x - *iout; + if (!f) { /* no fraction part */ + *fout = sign; + return NULL; + } + if (!(*iout & 0x7FFFFFFF)) { /* no integer part */ + *fout = *x; + return NULL; + } + while (!(f & 0x800000)) { + ex--; + f = f << 1; + } + *fout = sign | (ex << 23) | (f & 0x7FFFFF); + return NULL; +} + +char *test_copysign(uint32 *x, uint32 *y, uint32 *out) +{ + int ysign = y[0] & 0x80000000; + int xhigh = x[0] & 0x7fffffff; + + out[0] = ysign | xhigh; + out[1] = x[1]; + + /* There can be no error */ + return NULL; +} + +char *test_copysignf(uint32 *x, uint32 *y, uint32 *out) +{ + int ysign = y[0] & 0x80000000; + int xhigh = x[0] & 0x7fffffff; + + out[0] = ysign | xhigh; + + /* There can be no error */ + return NULL; +} + +char *test_isfinite(uint32 *x, uint32 *out) +{ + int xhigh = x[0]; + /* Being finite means that the exponent is not 0x7ff */ + if ((xhigh & 0x7ff00000) == 0x7ff00000) out[0] = 0; + else out[0] = 1; + return NULL; +} + +char *test_isfinitef(uint32 *x, uint32 *out) +{ + /* Being finite means that the exponent is not 0xff */ + if ((x[0] & 0x7f800000) == 0x7f800000) out[0] = 0; + else out[0] = 1; + return NULL; +} + +char *test_isinff(uint32 *x, uint32 *out) +{ + /* Being infinite means that our bottom 30 bits equate to 0x7f800000 */ + if ((x[0] & 0x7fffffff) == 0x7f800000) out[0] = 1; + else out[0] = 0; + return NULL; +} + +char *test_isinf(uint32 *x, uint32 *out) +{ + int xhigh = x[0]; + int xlow = x[1]; + /* Being infinite means that our fraction is zero and exponent is 0x7ff */ + if (((xhigh & 0x7fffffff) == 0x7ff00000) && (xlow == 0)) out[0] = 1; + else out[0] = 0; + return NULL; +} + +char *test_isnanf(uint32 *x, uint32 *out) +{ + /* Being NaN means that our exponent is 0xff and non-0 fraction */ + int exponent = x[0] & 0x7f800000; + int fraction = x[0] & 0x007fffff; + if ((exponent == 0x7f800000) && (fraction != 0)) out[0] = 1; + else out[0] = 0; + return NULL; +} + +char *test_isnan(uint32 *x, uint32 *out) +{ + /* Being NaN means that our exponent is 0x7ff and non-0 fraction */ + int exponent = x[0] & 0x7ff00000; + int fractionhigh = x[0] & 0x000fffff; + if ((exponent == 0x7ff00000) && ((fractionhigh != 0) || x[1] != 0)) + out[0] = 1; + else out[0] = 0; + return NULL; +} + +char *test_isnormalf(uint32 *x, uint32 *out) +{ + /* Being normal means exponent is not 0 and is not 0xff */ + int exponent = x[0] & 0x7f800000; + if (exponent == 0x7f800000) out[0] = 0; + else if (exponent == 0) out[0] = 0; + else out[0] = 1; + return NULL; +} + +char *test_isnormal(uint32 *x, uint32 *out) +{ + /* Being normal means exponent is not 0 and is not 0x7ff */ + int exponent = x[0] & 0x7ff00000; + if (exponent == 0x7ff00000) out[0] = 0; + else if (exponent == 0) out[0] = 0; + else out[0] = 1; + return NULL; +} + +char *test_signbitf(uint32 *x, uint32 *out) +{ + /* Sign bit is bit 31 */ + out[0] = (x[0] >> 31) & 1; + return NULL; +} + +char *test_signbit(uint32 *x, uint32 *out) +{ + /* Sign bit is bit 31 */ + out[0] = (x[0] >> 31) & 1; + return NULL; +} + +char *test_fpclassify(uint32 *x, uint32 *out) +{ + int exponent = (x[0] & 0x7ff00000) >> 20; + int fraction = (x[0] & 0x000fffff) | x[1]; + + if ((exponent == 0x00) && (fraction == 0)) out[0] = 0; + else if ((exponent == 0x00) && (fraction != 0)) out[0] = 4; + else if ((exponent == 0x7ff) && (fraction == 0)) out[0] = 3; + else if ((exponent == 0x7ff) && (fraction != 0)) out[0] = 7; + else out[0] = 5; + return NULL; +} + +char *test_fpclassifyf(uint32 *x, uint32 *out) +{ + int exponent = (x[0] & 0x7f800000) >> 23; + int fraction = x[0] & 0x007fffff; + + if ((exponent == 0x000) && (fraction == 0)) out[0] = 0; + else if ((exponent == 0x000) && (fraction != 0)) out[0] = 4; + else if ((exponent == 0xff) && (fraction == 0)) out[0] = 3; + else if ((exponent == 0xff) && (fraction != 0)) out[0] = 7; + else out[0] = 5; + return NULL; +} + +/* + * Internal function that compares doubles in x & y and returns -3, -2, -1, 0, + * 1 if they compare to be signaling, unordered, less than, equal or greater + * than. + */ +static int fpcmp4(uint32 *x, uint32 *y) +{ + int result = 0; + + /* + * Sort out whether results are ordered or not to begin with + * NaNs have exponent 0x7ff, and non-zero fraction. Signaling NaNs take + * higher priority than quiet ones. + */ + if ((x[0] & 0x7fffffff) >= 0x7ff80000) result = -2; + else if ((x[0] & 0x7fffffff) > 0x7ff00000) result = -3; + else if (((x[0] & 0x7fffffff) == 0x7ff00000) && (x[1] != 0)) result = -3; + if ((y[0] & 0x7fffffff) >= 0x7ff80000 && result != -3) result = -2; + else if ((y[0] & 0x7fffffff) > 0x7ff00000) result = -3; + else if (((y[0] & 0x7fffffff) == 0x7ff00000) && (y[1] != 0)) result = -3; + if (result != 0) return result; + + /* + * The two forms of zero are equal + */ + if (((x[0] & 0x7fffffff) == 0) && x[1] == 0 && + ((y[0] & 0x7fffffff) == 0) && y[1] == 0) + return 0; + + /* + * If x and y have different signs we can tell that they're not equal + * If x is +ve we have x > y return 1 - otherwise y is +ve return -1 + */ + if ((x[0] >> 31) != (y[0] >> 31)) + return ((x[0] >> 31) == 0) - ((y[0] >> 31) == 0); + + /* + * Now we have both signs the same, let's do an initial compare of the + * values. + * + * Whoever designed IEEE754's floating point formats is very clever and + * earns my undying admiration. Once you remove the sign-bit, the + * floating point numbers can be ordered using the standard <, ==, > + * operators will treating the fp-numbers as integers with that bit- + * pattern. + */ + if ((x[0] & 0x7fffffff) < (y[0] & 0x7fffffff)) result = -1; + else if ((x[0] & 0x7fffffff) > (y[0] & 0x7fffffff)) result = 1; + else if (x[1] < y[1]) result = -1; + else if (x[1] > y[1]) result = 1; + else result = 0; + + /* + * Now we return the result - is x is positive (and therefore so is y) we + * return the plain result - otherwise we negate it and return. + */ + if ((x[0] >> 31) == 0) return result; + else return -result; +} + +/* + * Internal function that compares floats in x & y and returns -3, -2, -1, 0, + * 1 if they compare to be signaling, unordered, less than, equal or greater + * than. + */ +static int fpcmp4f(uint32 *x, uint32 *y) +{ + int result = 0; + + /* + * Sort out whether results are ordered or not to begin with + * NaNs have exponent 0xff, and non-zero fraction - we have to handle all + * signaling cases over the quiet ones + */ + if ((x[0] & 0x7fffffff) >= 0x7fc00000) result = -2; + else if ((x[0] & 0x7fffffff) > 0x7f800000) result = -3; + if ((y[0] & 0x7fffffff) >= 0x7fc00000 && result != -3) result = -2; + else if ((y[0] & 0x7fffffff) > 0x7f800000) result = -3; + if (result != 0) return result; + + /* + * The two forms of zero are equal + */ + if (((x[0] & 0x7fffffff) == 0) && ((y[0] & 0x7fffffff) == 0)) + return 0; + + /* + * If x and y have different signs we can tell that they're not equal + * If x is +ve we have x > y return 1 - otherwise y is +ve return -1 + */ + if ((x[0] >> 31) != (y[0] >> 31)) + return ((x[0] >> 31) == 0) - ((y[0] >> 31) == 0); + + /* + * Now we have both signs the same, let's do an initial compare of the + * values. + * + * Whoever designed IEEE754's floating point formats is very clever and + * earns my undying admiration. Once you remove the sign-bit, the + * floating point numbers can be ordered using the standard <, ==, > + * operators will treating the fp-numbers as integers with that bit- + * pattern. + */ + if ((x[0] & 0x7fffffff) < (y[0] & 0x7fffffff)) result = -1; + else if ((x[0] & 0x7fffffff) > (y[0] & 0x7fffffff)) result = 1; + else result = 0; + + /* + * Now we return the result - is x is positive (and therefore so is y) we + * return the plain result - otherwise we negate it and return. + */ + if ((x[0] >> 31) == 0) return result; + else return -result; +} + +char *test_isgreater(uint32 *x, uint32 *y, uint32 *out) +{ + int result = fpcmp4(x, y); + *out = (result == 1); + return result == -3 ? "i" : NULL; +} + +char *test_isgreaterequal(uint32 *x, uint32 *y, uint32 *out) +{ + int result = fpcmp4(x, y); + *out = (result >= 0); + return result == -3 ? "i" : NULL; +} + +char *test_isless(uint32 *x, uint32 *y, uint32 *out) +{ + int result = fpcmp4(x, y); + *out = (result == -1); + return result == -3 ? "i" : NULL; +} + +char *test_islessequal(uint32 *x, uint32 *y, uint32 *out) +{ + int result = fpcmp4(x, y); + *out = (result == -1) || (result == 0); + return result == -3 ? "i" : NULL; +} + +char *test_islessgreater(uint32 *x, uint32 *y, uint32 *out) +{ + int result = fpcmp4(x, y); + *out = (result == -1) || (result == 1); + return result == -3 ? "i" : NULL; +} + +char *test_isunordered(uint32 *x, uint32 *y, uint32 *out) +{ + int normal = 0; + int result = fpcmp4(x, y); + + test_isnormal(x, out); + normal |= *out; + test_isnormal(y, out); + normal |= *out; + *out = (result == -2) || (result == -3); + return result == -3 ? "i" : NULL; +} + +char *test_isgreaterf(uint32 *x, uint32 *y, uint32 *out) +{ + int result = fpcmp4f(x, y); + *out = (result == 1); + return result == -3 ? "i" : NULL; +} + +char *test_isgreaterequalf(uint32 *x, uint32 *y, uint32 *out) +{ + int result = fpcmp4f(x, y); + *out = (result >= 0); + return result == -3 ? "i" : NULL; +} + +char *test_islessf(uint32 *x, uint32 *y, uint32 *out) +{ + int result = fpcmp4f(x, y); + *out = (result == -1); + return result == -3 ? "i" : NULL; +} + +char *test_islessequalf(uint32 *x, uint32 *y, uint32 *out) +{ + int result = fpcmp4f(x, y); + *out = (result == -1) || (result == 0); + return result == -3 ? "i" : NULL; +} + +char *test_islessgreaterf(uint32 *x, uint32 *y, uint32 *out) +{ + int result = fpcmp4f(x, y); + *out = (result == -1) || (result == 1); + return result == -3 ? "i" : NULL; +} + +char *test_isunorderedf(uint32 *x, uint32 *y, uint32 *out) +{ + int normal = 0; + int result = fpcmp4f(x, y); + + test_isnormalf(x, out); + normal |= *out; + test_isnormalf(y, out); + normal |= *out; + *out = (result == -2) || (result == -3); + return result == -3 ? "i" : NULL; +} |
