| 1 | /* Test floating-point arithmetic operations.
|
|---|
| 2 | Copyright (C) 1997, 1998 Free Software Foundation, Inc.
|
|---|
| 3 | This file is part of the GNU C Library.
|
|---|
| 4 |
|
|---|
| 5 | The GNU C Library is free software; you can redistribute it and/or
|
|---|
| 6 | modify it under the terms of the GNU Lesser General Public
|
|---|
| 7 | License as published by the Free Software Foundation; either
|
|---|
| 8 | version 2.1 of the License, or (at your option) any later version.
|
|---|
| 9 |
|
|---|
| 10 | The GNU C Library is distributed in the hope that it will be useful,
|
|---|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|---|
| 13 | Lesser General Public License for more details.
|
|---|
| 14 |
|
|---|
| 15 | You should have received a copy of the GNU Lesser General Public
|
|---|
| 16 | License along with the GNU C Library; if not, write to the Free
|
|---|
| 17 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|---|
| 18 | 02111-1307 USA. */
|
|---|
| 19 | #ifndef _GNU_SOURCE
|
|---|
| 20 | #define _GNU_SOURCE
|
|---|
| 21 | #endif
|
|---|
| 22 | #include <math.h>
|
|---|
| 23 | #include <stdio.h>
|
|---|
| 24 | #include <stdlib.h>
|
|---|
| 25 | #include <string.h>
|
|---|
| 26 | #include <fenv.h>
|
|---|
| 27 | #include <assert.h>
|
|---|
| 28 |
|
|---|
| 29 | #ifndef ESIZE
|
|---|
| 30 | typedef double tocheck_t;
|
|---|
| 31 | #define ESIZE 11
|
|---|
| 32 | #define MSIZE 52
|
|---|
| 33 | #define FUNC(x) x
|
|---|
| 34 | #endif
|
|---|
| 35 |
|
|---|
| 36 | #define R_NEAREST 1
|
|---|
| 37 | #define R_ZERO 2
|
|---|
| 38 | #define R_UP 4
|
|---|
| 39 | #define R_DOWN 8
|
|---|
| 40 | #define R_ALL (R_NEAREST|R_ZERO|R_UP|R_DOWN)
|
|---|
| 41 | static fenv_t rmodes[4];
|
|---|
| 42 | static const char * const rmnames[4] =
|
|---|
| 43 | { "nearest","zero","+Inf","-Inf" };
|
|---|
| 44 |
|
|---|
| 45 | typedef union {
|
|---|
| 46 | tocheck_t tc;
|
|---|
| 47 | unsigned char c[sizeof(tocheck_t)];
|
|---|
| 48 | } union_t;
|
|---|
| 49 |
|
|---|
| 50 | /* Don't try reading these in a font that doesn't distinguish
|
|---|
| 51 | O and zero. */
|
|---|
| 52 | typedef enum {
|
|---|
| 53 | P_Z = 0x0, /* 00000...0 */
|
|---|
| 54 | P_000O = 0x1, /* 00011...1 */
|
|---|
| 55 | P_001Z = 0x2, /* 00100...0 */
|
|---|
| 56 | P_00O = 0x3, /* 00111...1 */
|
|---|
| 57 | P_01Z = 0x4, /* 01000...0 */
|
|---|
| 58 | P_010O = 0x5, /* 01011...1 */
|
|---|
| 59 | P_011Z = 0x6, /* 01100...0 */
|
|---|
| 60 | P_0O = 0x7, /* 01111...1 */
|
|---|
| 61 | P_1Z = 0x8, /* 10000...0 */
|
|---|
| 62 | P_100O = 0x9, /* 10011...1 */
|
|---|
| 63 | P_101Z = 0xa, /* 10100...0 */
|
|---|
| 64 | P_10O = 0xb, /* 10111...1 */
|
|---|
| 65 | P_11Z = 0xc, /* 11000...0 */
|
|---|
| 66 | P_110O = 0xd, /* 11011...1 */
|
|---|
| 67 | P_111Z = 0xe, /* 11100...0 */
|
|---|
| 68 | P_O = 0xf, /* 11111...1 */
|
|---|
| 69 | P_Z1 = 0x11, /* 000...001 */
|
|---|
| 70 | P_Z10 = 0x12, /* 000...010 */
|
|---|
| 71 | P_Z11 = 0x13, /* 000...011 */
|
|---|
| 72 | P_0O00 = 0x14, /* 011...100 */
|
|---|
| 73 | P_0O01 = 0x15, /* 011...101 */
|
|---|
| 74 | P_0O0 = 0x16, /* 011...110 */
|
|---|
| 75 | P_1Z1 = 0x19, /* 100...001 */
|
|---|
| 76 | P_1Z10 = 0x1a, /* 100...010 */
|
|---|
| 77 | P_1Z11 = 0x1b, /* 100...011 */
|
|---|
| 78 | P_O00 = 0x1c, /* 111...100 */
|
|---|
| 79 | P_O01 = 0x1d, /* 111...101 */
|
|---|
| 80 | P_O0 = 0x1e, /* 111...110 */
|
|---|
| 81 | P_R = 0x20, /* rrr...rrr */ /* ('r' means random. ) */
|
|---|
| 82 | P_Ro = 0x21, /* rrr...rrr, with odd parity. */
|
|---|
| 83 | P_0R = 0x22, /* 0rr...rrr */
|
|---|
| 84 | P_1R = 0x23, /* 1rr...rrr */
|
|---|
| 85 | P_Rno = 0x24, /* rrr...rrr, but not all ones. */
|
|---|
| 86 | } pattern_t;
|
|---|
| 87 |
|
|---|
| 88 | static void
|
|---|
| 89 | pattern_fill(pattern_t ptn, unsigned char *start, int bitoffset, int count)
|
|---|
| 90 | {
|
|---|
| 91 | #define bitset(count, value) \
|
|---|
| 92 | start[(count)/8] = (start[(count)/8] & ~(1 << 7-(count)%8) \
|
|---|
| 93 | | (value) << 7-(count)%8)
|
|---|
| 94 | int i;
|
|---|
| 95 |
|
|---|
| 96 | if (ptn >= 0 && ptn <= 0xf)
|
|---|
| 97 | {
|
|---|
| 98 | /* Patterns between 0 and 0xF have the following format:
|
|---|
| 99 | The LSBit is used to fill the last n-3 bits of the pattern;
|
|---|
| 100 | The next 3 bits are the first 3 bits of the pattern. */
|
|---|
| 101 | for (i = 0; i < count; i++)
|
|---|
| 102 | if (i < 3)
|
|---|
| 103 | bitset((bitoffset+i), ptn >> (3-i) & 1);
|
|---|
| 104 | else
|
|---|
| 105 | bitset((bitoffset+i), ptn >> 0 & 1);
|
|---|
| 106 | }
|
|---|
| 107 | else if (ptn <= 0x1f)
|
|---|
| 108 | {
|
|---|
| 109 | /* Patterns between 0x10 and 0x1F have the following format:
|
|---|
| 110 | The two LSBits are the last two bits of the pattern;
|
|---|
| 111 | The 0x8 bit is the first bit of the pattern;
|
|---|
| 112 | The 0x4 bit is used to fill the remainder. */
|
|---|
| 113 | for (i = 0; i < count; i++)
|
|---|
| 114 | if (i == 0)
|
|---|
| 115 | bitset((bitoffset+i), ptn >> 3 & 1);
|
|---|
| 116 | else if (i >= count-2)
|
|---|
| 117 | bitset((bitoffset+i), ptn >> (count-1-i) & 1);
|
|---|
| 118 | else
|
|---|
| 119 | bitset((bitoffset+i), ptn >> 2 & 1);
|
|---|
| 120 | }
|
|---|
| 121 | else switch (ptn)
|
|---|
| 122 | {
|
|---|
| 123 | case P_0R: case P_1R:
|
|---|
| 124 | assert(count > 0);
|
|---|
| 125 | bitset(bitoffset, ptn & 1);
|
|---|
| 126 | count--;
|
|---|
| 127 | bitoffset++;
|
|---|
| 128 | case P_R:
|
|---|
| 129 | for (; count > 0; count--, bitoffset++)
|
|---|
| 130 | bitset(bitoffset, rand() & 1);
|
|---|
| 131 | break;
|
|---|
| 132 | case P_Ro:
|
|---|
| 133 | {
|
|---|
| 134 | int op = 1;
|
|---|
| 135 | assert(count > 0);
|
|---|
| 136 | for (; count > 1; count--, bitoffset++)
|
|---|
| 137 | bitset(bitoffset, op ^= (rand() & 1));
|
|---|
| 138 | bitset(bitoffset, op);
|
|---|
| 139 | break;
|
|---|
| 140 | }
|
|---|
| 141 | case P_Rno:
|
|---|
| 142 | {
|
|---|
| 143 | int op = 1;
|
|---|
| 144 | assert(count > 0);
|
|---|
| 145 | for (; count > 1; count--, bitoffset++)
|
|---|
| 146 | {
|
|---|
| 147 | int r = rand() & 1;
|
|---|
| 148 | op &= r;
|
|---|
| 149 | bitset(bitoffset, r);
|
|---|
| 150 | }
|
|---|
| 151 | bitset(bitoffset, rand() & (op ^ 1));
|
|---|
| 152 | break;
|
|---|
| 153 | }
|
|---|
| 154 |
|
|---|
| 155 | default:
|
|---|
| 156 | assert(0);
|
|---|
| 157 | }
|
|---|
| 158 | #undef bitset
|
|---|
| 159 | }
|
|---|
| 160 |
|
|---|
| 161 | static tocheck_t
|
|---|
| 162 | pattern(int negative, pattern_t exp, pattern_t mant)
|
|---|
| 163 | {
|
|---|
| 164 | union_t result;
|
|---|
| 165 | #if 0
|
|---|
| 166 | int i;
|
|---|
| 167 | #endif
|
|---|
| 168 |
|
|---|
| 169 | pattern_fill(negative ? P_O : P_Z, result.c, 0, 1);
|
|---|
| 170 | pattern_fill(exp, result.c, 1, ESIZE);
|
|---|
| 171 | pattern_fill(mant, result.c, ESIZE+1, MSIZE);
|
|---|
| 172 | #if 0
|
|---|
| 173 | printf("neg=%d exp=%02x mant=%02x: ", negative, exp, mant);
|
|---|
| 174 | for (i = 0; i < sizeof(tocheck_t); i++)
|
|---|
| 175 | printf("%02x", result.c[i]);
|
|---|
| 176 | printf("\n");
|
|---|
| 177 | #endif
|
|---|
| 178 | return result.tc;
|
|---|
| 179 | }
|
|---|
| 180 |
|
|---|
| 181 | /* Return the closest different tocheck_t to 'x' in the direction of
|
|---|
| 182 | 'direction', or 'x' if there is no such value. Assumes 'x' is not
|
|---|
| 183 | a NaN. */
|
|---|
| 184 | static tocheck_t
|
|---|
| 185 | delta(tocheck_t x, int direction)
|
|---|
| 186 | {
|
|---|
| 187 | union_t xx;
|
|---|
| 188 | int i;
|
|---|
| 189 |
|
|---|
| 190 | xx.tc = x;
|
|---|
| 191 | if (xx.c[0] & 0x80)
|
|---|
| 192 | direction = -direction;
|
|---|
| 193 | if (direction == +1)
|
|---|
| 194 | {
|
|---|
| 195 | union_t tx;
|
|---|
| 196 | tx.tc = pattern(xx.c[0] >> 7, P_O, P_Z);
|
|---|
| 197 | if (memcmp(tx.c, xx.c, sizeof(tocheck_t)) == 0)
|
|---|
| 198 | return x;
|
|---|
| 199 | }
|
|---|
| 200 | for (i = sizeof(tocheck_t)-1; i > 0; i--)
|
|---|
| 201 | {
|
|---|
| 202 | xx.c[i] += direction;
|
|---|
| 203 | if (xx.c[i] != (direction > 0 ? 0 : 0xff))
|
|---|
| 204 | return xx.tc;
|
|---|
| 205 | }
|
|---|
| 206 | if (direction < 0 && (xx.c[0] & 0x7f) == 0)
|
|---|
| 207 | return pattern(~(xx.c[0] >> 7) & 1, P_Z, P_Z1);
|
|---|
| 208 | else
|
|---|
| 209 | {
|
|---|
| 210 | xx.c[0] += direction;
|
|---|
| 211 | return xx.tc;
|
|---|
| 212 | }
|
|---|
| 213 | }
|
|---|
| 214 |
|
|---|
| 215 | static int nerrors = 0;
|
|---|
| 216 |
|
|---|
| 217 | #ifdef FE_ALL_INVALID
|
|---|
| 218 | static const int all_exceptions = FE_ALL_INVALID | FE_ALL_EXCEPT;
|
|---|
| 219 | #else
|
|---|
| 220 | static const int all_exceptions = FE_ALL_EXCEPT;
|
|---|
| 221 | #endif
|
|---|
| 222 |
|
|---|
| 223 | static void
|
|---|
| 224 | check_result(int line, const char *rm, tocheck_t expected, tocheck_t actual)
|
|---|
| 225 | {
|
|---|
| 226 | if (memcmp(&expected, &actual, sizeof(tocheck_t)) != 0)
|
|---|
| 227 | {
|
|---|
| 228 | unsigned char *ex, *ac;
|
|---|
| 229 | size_t i;
|
|---|
| 230 |
|
|---|
| 231 | printf("%s:%d:round %s:result failed\n"
|
|---|
| 232 | " expected result 0x", __FILE__, line, rm);
|
|---|
| 233 | ex = (unsigned char *)&expected;
|
|---|
| 234 | ac = (unsigned char *)&actual;
|
|---|
| 235 | for (i = 0; i < sizeof(tocheck_t); i++)
|
|---|
| 236 | printf("%02x", ex[i]);
|
|---|
| 237 | printf(" got 0x");
|
|---|
| 238 | for (i = 0; i < sizeof(tocheck_t); i++)
|
|---|
| 239 | printf("%02x", ac[i]);
|
|---|
| 240 | printf("\n");
|
|---|
| 241 | nerrors++;
|
|---|
| 242 | }
|
|---|
| 243 | }
|
|---|
| 244 |
|
|---|
| 245 | static const struct {
|
|---|
| 246 | int except;
|
|---|
| 247 | const char *name;
|
|---|
| 248 | } excepts[] = {
|
|---|
| 249 | #define except_entry(ex) { ex, #ex } ,
|
|---|
| 250 | #ifdef FE_INEXACT
|
|---|
| 251 | except_entry(FE_INEXACT)
|
|---|
| 252 | #else
|
|---|
| 253 | # define FE_INEXACT 0
|
|---|
| 254 | #endif
|
|---|
| 255 | #ifdef FE_DIVBYZERO
|
|---|
| 256 | except_entry(FE_DIVBYZERO)
|
|---|
| 257 | #else
|
|---|
| 258 | # define FE_DIVBYZERO 0
|
|---|
| 259 | #endif
|
|---|
| 260 | #ifdef FE_UNDERFLOW
|
|---|
| 261 | except_entry(FE_UNDERFLOW)
|
|---|
| 262 | #else
|
|---|
| 263 | # define FE_UNDERFLOW 0
|
|---|
| 264 | #endif
|
|---|
| 265 | #ifdef FE_OVERFLOW
|
|---|
| 266 | except_entry(FE_OVERFLOW)
|
|---|
| 267 | #else
|
|---|
| 268 | # define FE_OVERFLOW 0
|
|---|
| 269 | #endif
|
|---|
| 270 | #ifdef FE_INVALID
|
|---|
| 271 | except_entry(FE_INVALID)
|
|---|
| 272 | #else
|
|---|
| 273 | # define FE_INVALID 0
|
|---|
| 274 | #endif
|
|---|
| 275 | #ifdef FE_INVALID_SNAN
|
|---|
| 276 | except_entry(FE_INVALID_SNAN)
|
|---|
| 277 | #else
|
|---|
| 278 | # define FE_INVALID_SNAN FE_INVALID
|
|---|
| 279 | #endif
|
|---|
| 280 | #ifdef FE_INVALID_ISI
|
|---|
| 281 | except_entry(FE_INVALID_ISI)
|
|---|
| 282 | #else
|
|---|
| 283 | # define FE_INVALID_ISI FE_INVALID
|
|---|
| 284 | #endif
|
|---|
| 285 | #ifdef FE_INVALID_IDI
|
|---|
| 286 | except_entry(FE_INVALID_IDI)
|
|---|
| 287 | #else
|
|---|
| 288 | # define FE_INVALID_IDI FE_INVALID
|
|---|
| 289 | #endif
|
|---|
| 290 | #ifdef FE_INVALID_ZDZ
|
|---|
| 291 | except_entry(FE_INVALID_ZDZ)
|
|---|
| 292 | #else
|
|---|
| 293 | # define FE_INVALID_ZDZ FE_INVALID
|
|---|
| 294 | #endif
|
|---|
| 295 | #ifdef FE_INVALID_COMPARE
|
|---|
| 296 | except_entry(FE_INVALID_COMPARE)
|
|---|
| 297 | #else
|
|---|
| 298 | # define FE_INVALID_COMPARE FE_INVALID
|
|---|
| 299 | #endif
|
|---|
| 300 | #ifdef FE_INVALID_SOFTWARE
|
|---|
| 301 | except_entry(FE_INVALID_SOFTWARE)
|
|---|
| 302 | #else
|
|---|
| 303 | # define FE_INVALID_SOFTWARE FE_INVALID
|
|---|
| 304 | #endif
|
|---|
| 305 | #ifdef FE_INVALID_SQRT
|
|---|
| 306 | except_entry(FE_INVALID_SQRT)
|
|---|
| 307 | #else
|
|---|
| 308 | # define FE_INVALID_SQRT FE_INVALID
|
|---|
| 309 | #endif
|
|---|
| 310 | #ifdef FE_INVALID_INTEGER_CONVERSION
|
|---|
| 311 | except_entry(FE_INVALID_INTEGER_CONVERSION)
|
|---|
| 312 | #else
|
|---|
| 313 | # define FE_INVALID_INTEGER_CONVERSION FE_INVALID
|
|---|
| 314 | #endif
|
|---|
| 315 | };
|
|---|
| 316 |
|
|---|
| 317 | static int excepts_missing = 0;
|
|---|
| 318 |
|
|---|
| 319 | static void
|
|---|
| 320 | check_excepts(int line, const char *rm, int expected, int actual)
|
|---|
| 321 | {
|
|---|
| 322 | if (expected & excepts_missing)
|
|---|
| 323 | expected = expected & ~excepts_missing | FE_INVALID_SNAN;
|
|---|
| 324 | if ((expected & all_exceptions) != actual)
|
|---|
| 325 | {
|
|---|
| 326 | size_t i;
|
|---|
| 327 | printf("%s:%d:round %s:exceptions failed\n"
|
|---|
| 328 | " expected exceptions ", __FILE__, line,rm);
|
|---|
| 329 | for (i = 0; i < sizeof(excepts)/sizeof(excepts[0]); i++)
|
|---|
| 330 | if (expected & excepts[i].except)
|
|---|
| 331 | printf("%s ",excepts[i].name);
|
|---|
| 332 | if ((expected & all_exceptions) == 0)
|
|---|
| 333 | printf("- ");
|
|---|
| 334 | printf("got");
|
|---|
| 335 | for (i = 0; i < sizeof(excepts)/sizeof(excepts[0]); i++)
|
|---|
| 336 | if (actual & excepts[i].except)
|
|---|
| 337 | printf(" %s",excepts[i].name);
|
|---|
| 338 | if ((actual & all_exceptions) == 0)
|
|---|
| 339 | printf("- ");
|
|---|
| 340 | printf(".\n");
|
|---|
| 341 | nerrors++;
|
|---|
| 342 | }
|
|---|
| 343 | }
|
|---|
| 344 |
|
|---|
| 345 | typedef enum {
|
|---|
| 346 | B_ADD, B_SUB, B_MUL, B_DIV, B_NEG, B_ABS, B_SQRT
|
|---|
| 347 | } op_t;
|
|---|
| 348 | typedef struct {
|
|---|
| 349 | int line;
|
|---|
| 350 | op_t op;
|
|---|
| 351 | int a_sgn;
|
|---|
| 352 | pattern_t a_exp, a_mant;
|
|---|
| 353 | int b_sgn;
|
|---|
| 354 | pattern_t b_exp, b_mant;
|
|---|
| 355 | int rmode;
|
|---|
| 356 | int excepts;
|
|---|
| 357 | int x_sgn;
|
|---|
| 358 | pattern_t x_exp, x_mant;
|
|---|
| 359 | } optest_t;
|
|---|
| 360 | static const optest_t optests[] = {
|
|---|
| 361 | /* Additions of zero. */
|
|---|
| 362 | {__LINE__,B_ADD, 0,P_Z,P_Z, 0,P_Z,P_Z, R_ALL,0, 0,P_Z,P_Z },
|
|---|
| 363 | {__LINE__,B_ADD, 1,P_Z,P_Z, 0,P_Z,P_Z, R_ALL & ~R_DOWN,0, 0,P_Z,P_Z },
|
|---|
| 364 | {__LINE__,B_ADD, 1,P_Z,P_Z, 0,P_Z,P_Z, R_DOWN,0, 1,P_Z,P_Z },
|
|---|
| 365 | {__LINE__,B_ADD, 1,P_Z,P_Z, 1,P_Z,P_Z, R_ALL,0, 1,P_Z,P_Z },
|
|---|
| 366 |
|
|---|
| 367 | /* Additions with NaN. */
|
|---|
| 368 | {__LINE__,B_ADD, 0,P_O,P_101Z, 0,P_Z,P_Z, R_ALL,0, 0,P_O,P_101Z },
|
|---|
| 369 | {__LINE__,B_ADD, 0,P_O,P_01Z, 0,P_Z,P_Z, R_ALL,
|
|---|
| 370 | FE_INVALID | FE_INVALID_SNAN, 0,P_O,P_11Z },
|
|---|
| 371 | {__LINE__,B_ADD, 0,P_O,P_Z, 0,P_O,P_0O, R_ALL,
|
|---|
| 372 | FE_INVALID | FE_INVALID_SNAN, 0,P_O,P_O },
|
|---|
| 373 | {__LINE__,B_ADD, 0,P_Z,P_Z, 0,P_O,P_11Z, R_ALL,0, 0,P_O,P_11Z },
|
|---|
| 374 | {__LINE__,B_ADD, 0,P_O,P_001Z, 0,P_O,P_001Z, R_ALL,
|
|---|
| 375 | FE_INVALID | FE_INVALID_SNAN, 0,P_O,P_101Z },
|
|---|
| 376 | {__LINE__,B_ADD, 0,P_O,P_1Z, 0,P_Z,P_Z, R_ALL,0, 0,P_O,P_1Z },
|
|---|
| 377 | {__LINE__,B_ADD, 0,P_0O,P_Z, 0,P_O,P_10O, R_ALL,0, 0,P_O,P_10O },
|
|---|
| 378 |
|
|---|
| 379 | /* Additions with infinity. */
|
|---|
| 380 | {__LINE__,B_ADD, 0,P_O,P_Z, 0,P_Z,P_Z, R_ALL,0, 0,P_O,P_Z },
|
|---|
| 381 | {__LINE__,B_ADD, 0,P_O,P_Z, 1,P_Z,P_Z, R_ALL,0, 0,P_O,P_Z },
|
|---|
| 382 | {__LINE__,B_ADD, 1,P_O,P_Z, 0,P_Z,P_Z, R_ALL,0, 1,P_O,P_Z },
|
|---|
| 383 | {__LINE__,B_ADD, 1,P_O,P_Z, 1,P_Z,P_Z, R_ALL,0, 1,P_O,P_Z },
|
|---|
| 384 | {__LINE__,B_ADD, 0,P_O,P_Z, 0,P_O,P_Z, R_ALL,0, 0,P_O,P_Z },
|
|---|
| 385 | {__LINE__,B_ADD, 1,P_O,P_Z, 1,P_O,P_Z, R_ALL,0, 1,P_O,P_Z },
|
|---|
| 386 | {__LINE__,B_ADD, 0,P_O,P_Z, 1,P_O,P_Z, R_ALL,
|
|---|
| 387 | FE_INVALID | FE_INVALID_ISI, 0,P_O,P_1Z },
|
|---|
| 388 | {__LINE__,B_ADD, 1,P_O,P_Z, 0,P_O,P_Z, R_ALL,
|
|---|
| 389 | FE_INVALID | FE_INVALID_ISI, 0,P_O,P_1Z },
|
|---|
| 390 | {__LINE__,B_ADD, 0,P_O,P_Z, 0,P_0O,P_Z, R_ALL,0, 0,P_O,P_Z },
|
|---|
| 391 | {__LINE__,B_ADD, 1,P_O,P_Z, 0,P_0O,P_Z, R_ALL,0, 1,P_O,P_Z },
|
|---|
| 392 | {__LINE__,B_ADD, 0,P_O,P_Z, 1,P_0O,P_Z, R_ALL,0, 0,P_O,P_Z },
|
|---|
| 393 | {__LINE__,B_ADD, 1,P_O,P_Z, 1,P_0O,P_Z, R_ALL,0, 1,P_O,P_Z },
|
|---|
| 394 |
|
|---|
| 395 | /* Overflow (and zero). */
|
|---|
| 396 | {__LINE__,B_ADD, 0,P_O0,P_Z, 0,P_O0,P_Z, R_NEAREST | R_UP,
|
|---|
| 397 | FE_INEXACT | FE_OVERFLOW, 0,P_O,P_Z },
|
|---|
| 398 | {__LINE__,B_ADD, 0,P_O0,P_Z, 0,P_O0,P_Z, R_ZERO | R_DOWN,
|
|---|
| 399 | FE_INEXACT | FE_OVERFLOW, 0,P_O0,P_O },
|
|---|
| 400 | {__LINE__,B_ADD, 1,P_O0,P_Z, 1,P_O0,P_Z, R_NEAREST | R_DOWN,
|
|---|
| 401 | FE_INEXACT | FE_OVERFLOW, 1,P_O,P_Z },
|
|---|
| 402 | {__LINE__,B_ADD, 1,P_O0,P_Z, 1,P_O0,P_Z, R_ZERO | R_UP,
|
|---|
| 403 | FE_INEXACT | FE_OVERFLOW, 1,P_O0,P_O },
|
|---|
| 404 | {__LINE__,B_ADD, 0,P_O0,P_Z, 1,P_O0,P_Z, R_ALL & ~R_DOWN,
|
|---|
| 405 | 0, 0,P_Z,P_Z },
|
|---|
| 406 | {__LINE__,B_ADD, 0,P_O0,P_Z, 1,P_O0,P_Z, R_DOWN,
|
|---|
| 407 | 0, 1,P_Z,P_Z },
|
|---|
| 408 |
|
|---|
| 409 | /* Negation. */
|
|---|
| 410 | {__LINE__,B_NEG, 0,P_Z,P_Z, 0,0,0, R_ALL, 0, 1,P_Z,P_Z },
|
|---|
| 411 | {__LINE__,B_NEG, 1,P_Z,P_Z, 0,0,0, R_ALL, 0, 0,P_Z,P_Z },
|
|---|
| 412 | {__LINE__,B_NEG, 0,P_O,P_Z, 0,0,0, R_ALL, 0, 1,P_O,P_Z },
|
|---|
| 413 | {__LINE__,B_NEG, 1,P_O,P_Z, 0,0,0, R_ALL, 0, 0,P_O,P_Z },
|
|---|
| 414 | {__LINE__,B_NEG, 0,P_O,P_1Z, 0,0,0, R_ALL, 0, 1,P_O,P_1Z },
|
|---|
| 415 | {__LINE__,B_NEG, 1,P_O,P_1Z, 0,0,0, R_ALL, 0, 0,P_O,P_1Z },
|
|---|
| 416 | {__LINE__,B_NEG, 0,P_O,P_01Z, 0,0,0, R_ALL, 0, 1,P_O,P_01Z },
|
|---|
| 417 | {__LINE__,B_NEG, 1,P_O,P_01Z, 0,0,0, R_ALL, 0, 0,P_O,P_01Z },
|
|---|
| 418 | {__LINE__,B_NEG, 0,P_1Z,P_1Z1, 0,0,0, R_ALL, 0, 1,P_1Z,P_1Z1 },
|
|---|
| 419 | {__LINE__,B_NEG, 1,P_1Z,P_1Z1, 0,0,0, R_ALL, 0, 0,P_1Z,P_1Z1 },
|
|---|
| 420 | {__LINE__,B_NEG, 0,P_Z,P_Z1, 0,0,0, R_ALL, 0, 1,P_Z,P_Z1 },
|
|---|
| 421 | {__LINE__,B_NEG, 1,P_Z,P_Z1, 0,0,0, R_ALL, 0, 0,P_Z,P_Z1 },
|
|---|
| 422 |
|
|---|
| 423 | /* Absolute value. */
|
|---|
| 424 | {__LINE__,B_ABS, 0,P_Z,P_Z, 0,0,0, R_ALL, 0, 0,P_Z,P_Z },
|
|---|
| 425 | {__LINE__,B_ABS, 1,P_Z,P_Z, 0,0,0, R_ALL, 0, 0,P_Z,P_Z },
|
|---|
| 426 | {__LINE__,B_ABS, 0,P_O,P_Z, 0,0,0, R_ALL, 0, 0,P_O,P_Z },
|
|---|
| 427 | {__LINE__,B_ABS, 1,P_O,P_Z, 0,0,0, R_ALL, 0, 0,P_O,P_Z },
|
|---|
| 428 | {__LINE__,B_ABS, 0,P_O,P_1Z, 0,0,0, R_ALL, 0, 0,P_O,P_1Z },
|
|---|
| 429 | {__LINE__,B_ABS, 1,P_O,P_1Z, 0,0,0, R_ALL, 0, 0,P_O,P_1Z },
|
|---|
| 430 | {__LINE__,B_ABS, 0,P_O,P_01Z, 0,0,0, R_ALL, 0, 0,P_O,P_01Z },
|
|---|
| 431 | {__LINE__,B_ABS, 1,P_O,P_01Z, 0,0,0, R_ALL, 0, 0,P_O,P_01Z },
|
|---|
| 432 | {__LINE__,B_ABS, 0,P_1Z,P_1Z1, 0,0,0, R_ALL, 0, 0,P_1Z,P_1Z1 },
|
|---|
| 433 | {__LINE__,B_ABS, 1,P_1Z,P_1Z1, 0,0,0, R_ALL, 0, 0,P_1Z,P_1Z1 },
|
|---|
| 434 | {__LINE__,B_ABS, 0,P_Z,P_Z1, 0,0,0, R_ALL, 0, 0,P_Z,P_Z1 },
|
|---|
| 435 | {__LINE__,B_ABS, 1,P_Z,P_Z1, 0,0,0, R_ALL, 0, 0,P_Z,P_Z1 },
|
|---|
| 436 |
|
|---|
| 437 | /* Square root. */
|
|---|
| 438 | {__LINE__,B_SQRT, 0,P_Z,P_Z, 0,0,0, R_ALL, 0, 0,P_Z,P_Z },
|
|---|
| 439 | {__LINE__,B_SQRT, 1,P_Z,P_Z, 0,0,0, R_ALL, 0, 1,P_Z,P_Z },
|
|---|
| 440 | {__LINE__,B_SQRT, 0,P_O,P_1Z, 0,0,0, R_ALL, 0, 0,P_O,P_1Z },
|
|---|
| 441 | {__LINE__,B_SQRT, 1,P_O,P_1Z, 0,0,0, R_ALL, 0, 1,P_O,P_1Z },
|
|---|
| 442 | {__LINE__,B_SQRT, 0,P_O,P_01Z, 0,0,0, R_ALL,
|
|---|
| 443 | FE_INVALID | FE_INVALID_SNAN, 0,P_O,P_11Z },
|
|---|
| 444 | {__LINE__,B_SQRT, 1,P_O,P_01Z, 0,0,0, R_ALL,
|
|---|
| 445 | FE_INVALID | FE_INVALID_SNAN, 1,P_O,P_11Z },
|
|---|
| 446 |
|
|---|
| 447 | {__LINE__,B_SQRT, 0,P_O,P_Z, 0,0,0, R_ALL, 0, 0,P_O,P_Z },
|
|---|
| 448 | {__LINE__,B_SQRT, 0,P_0O,P_Z, 0,0,0, R_ALL, 0, 0,P_0O,P_Z },
|
|---|
| 449 |
|
|---|
| 450 | {__LINE__,B_SQRT, 1,P_O,P_Z, 0,0,0, R_ALL,
|
|---|
| 451 | FE_INVALID | FE_INVALID_SQRT, 0,P_O,P_1Z },
|
|---|
| 452 | {__LINE__,B_SQRT, 1,P_1Z,P_1Z1, 0,0,0, R_ALL,
|
|---|
| 453 | FE_INVALID | FE_INVALID_SQRT, 0,P_O,P_1Z },
|
|---|
| 454 | {__LINE__,B_SQRT, 1,P_Z,P_Z1, 0,0,0, R_ALL,
|
|---|
| 455 | FE_INVALID | FE_INVALID_SQRT, 0,P_O,P_1Z },
|
|---|
| 456 |
|
|---|
| 457 | };
|
|---|
| 458 |
|
|---|
| 459 | static void
|
|---|
| 460 | check_op(void)
|
|---|
| 461 | {
|
|---|
| 462 | size_t i;
|
|---|
| 463 | int j;
|
|---|
| 464 | tocheck_t r, a, b, x;
|
|---|
| 465 | int raised;
|
|---|
| 466 |
|
|---|
| 467 | for (i = 0; i < sizeof(optests)/sizeof(optests[0]); i++)
|
|---|
| 468 | {
|
|---|
| 469 | a = pattern(optests[i].a_sgn, optests[i].a_exp,
|
|---|
| 470 | optests[i].a_mant);
|
|---|
| 471 | b = pattern(optests[i].b_sgn, optests[i].b_exp,
|
|---|
| 472 | optests[i].b_mant);
|
|---|
| 473 | x = pattern(optests[i].x_sgn, optests[i].x_exp,
|
|---|
| 474 | optests[i].x_mant);
|
|---|
| 475 | for (j = 0; j < 4; j++)
|
|---|
| 476 | if (optests[i].rmode & 1<<j)
|
|---|
| 477 | {
|
|---|
| 478 | fesetenv(rmodes+j);
|
|---|
| 479 | switch (optests[i].op)
|
|---|
| 480 | {
|
|---|
| 481 | case B_ADD: r = a + b; break;
|
|---|
| 482 | case B_SUB: r = a - b; break;
|
|---|
| 483 | case B_MUL: r = a * b; break;
|
|---|
| 484 | case B_DIV: r = a / b; break;
|
|---|
| 485 | case B_NEG: r = -a; break;
|
|---|
| 486 | case B_ABS: r = FUNC(fabs)(a); break;
|
|---|
| 487 | case B_SQRT: r = FUNC(sqrt)(a); break;
|
|---|
| 488 | }
|
|---|
| 489 | raised = fetestexcept(all_exceptions);
|
|---|
| 490 | check_result(optests[i].line,rmnames[j],x,r);
|
|---|
| 491 | check_excepts(optests[i].line,rmnames[j],
|
|---|
| 492 | optests[i].excepts,raised);
|
|---|
| 493 | }
|
|---|
| 494 | }
|
|---|
| 495 | }
|
|---|
| 496 |
|
|---|
| 497 | static void
|
|---|
| 498 | fail_xr(int line, const char *rm, tocheck_t x, tocheck_t r, tocheck_t xx,
|
|---|
| 499 | int xflag)
|
|---|
| 500 | {
|
|---|
| 501 | size_t i;
|
|---|
| 502 | unsigned char *cx, *cr, *cxx;
|
|---|
| 503 |
|
|---|
| 504 | printf("%s:%d:round %s:fail\n with x=0x", __FILE__, line,rm);
|
|---|
| 505 | cx = (unsigned char *)&x;
|
|---|
| 506 | cr = (unsigned char *)&r;
|
|---|
| 507 | cxx = (unsigned char *)&xx;
|
|---|
| 508 | for (i = 0; i < sizeof(tocheck_t); i++)
|
|---|
| 509 | printf("%02x", cx[i]);
|
|---|
| 510 | printf(" r=0x");
|
|---|
| 511 | for (i = 0; i < sizeof(tocheck_t); i++)
|
|---|
| 512 | printf("%02x", cr[i]);
|
|---|
| 513 | printf(" xx=0x");
|
|---|
| 514 | for (i = 0; i < sizeof(tocheck_t); i++)
|
|---|
| 515 | printf("%02x", cxx[i]);
|
|---|
| 516 | printf(" inexact=%d\n", xflag != 0);
|
|---|
| 517 | nerrors++;
|
|---|
| 518 | }
|
|---|
| 519 |
|
|---|
| 520 | static void
|
|---|
| 521 | check_sqrt(tocheck_t a)
|
|---|
| 522 | {
|
|---|
| 523 | int j;
|
|---|
| 524 | tocheck_t r0, r1, r2, x0, x1, x2;
|
|---|
| 525 | int raised = 0;
|
|---|
| 526 | int ok;
|
|---|
| 527 |
|
|---|
| 528 | for (j = 0; j < 4; j++)
|
|---|
| 529 | {
|
|---|
| 530 | int excepts;
|
|---|
| 531 |
|
|---|
| 532 | fesetenv(rmodes+j);
|
|---|
| 533 | r1 = FUNC(sqrt)(a);
|
|---|
| 534 | excepts = fetestexcept(all_exceptions);
|
|---|
| 535 | fesetenv(FE_DFL_ENV);
|
|---|
| 536 | raised |= excepts & ~FE_INEXACT;
|
|---|
| 537 | x1 = r1 * r1 - a;
|
|---|
| 538 | if (excepts & FE_INEXACT)
|
|---|
| 539 | {
|
|---|
| 540 | r0 = delta(r1,-1); r2 = delta(r1,1);
|
|---|
| 541 | switch (1 << j)
|
|---|
| 542 | {
|
|---|
| 543 | case R_NEAREST:
|
|---|
| 544 | x0 = r0 * r0 - a; x2 = r2 * r2 - a;
|
|---|
| 545 | ok = fabs(x0) >= fabs(x1) && fabs(x1) <= fabs(x2);
|
|---|
| 546 | break;
|
|---|
| 547 | case R_ZERO: case R_DOWN:
|
|---|
| 548 | x2 = r2 * r2 - a;
|
|---|
| 549 | ok = x1 <= 0 && x2 >= 0;
|
|---|
| 550 | break;
|
|---|
| 551 | case R_UP:
|
|---|
| 552 | x0 = r0 * r0 - a;
|
|---|
| 553 | ok = x1 >= 0 && x0 <= 0;
|
|---|
| 554 | break;
|
|---|
| 555 | default:
|
|---|
| 556 | assert(0);
|
|---|
| 557 | }
|
|---|
| 558 | }
|
|---|
| 559 | else
|
|---|
| 560 | ok = x1 == 0;
|
|---|
| 561 | if (!ok)
|
|---|
| 562 | fail_xr(__LINE__,rmnames[j],a,r1,x1,excepts&FE_INEXACT);
|
|---|
| 563 | }
|
|---|
| 564 | check_excepts(__LINE__,"all",0,raised);
|
|---|
| 565 | }
|
|---|
| 566 |
|
|---|
| 567 | int main(int argc, char **argv)
|
|---|
| 568 | {
|
|---|
| 569 | int i;
|
|---|
| 570 |
|
|---|
| 571 | _LIB_VERSION = _IEEE_;
|
|---|
| 572 |
|
|---|
| 573 | /* Set up environments for rounding modes. */
|
|---|
| 574 | fesetenv(FE_DFL_ENV);
|
|---|
| 575 | fesetround(FE_TONEAREST);
|
|---|
| 576 | fegetenv(rmodes+0);
|
|---|
| 577 | fesetround(FE_TOWARDZERO);
|
|---|
| 578 | fegetenv(rmodes+1);
|
|---|
| 579 | fesetround(FE_UPWARD);
|
|---|
| 580 | fegetenv(rmodes+2);
|
|---|
| 581 | fesetround(FE_DOWNWARD);
|
|---|
| 582 | fegetenv(rmodes+3);
|
|---|
| 583 |
|
|---|
| 584 | #if defined(FE_INVALID_SOFTWARE) || defined(FE_INVALID_SQRT)
|
|---|
| 585 | /* There's this really stupid feature of the 601... */
|
|---|
| 586 | fesetenv(FE_DFL_ENV);
|
|---|
| 587 | feraiseexcept(FE_INVALID_SOFTWARE);
|
|---|
| 588 | if (!fetestexcept(FE_INVALID_SOFTWARE))
|
|---|
| 589 | excepts_missing |= FE_INVALID_SOFTWARE;
|
|---|
| 590 | fesetenv(FE_DFL_ENV);
|
|---|
| 591 | feraiseexcept(FE_INVALID_SQRT);
|
|---|
| 592 | if (!fetestexcept(FE_INVALID_SQRT))
|
|---|
| 593 | excepts_missing |= FE_INVALID_SQRT;
|
|---|
| 594 | #endif
|
|---|
| 595 |
|
|---|
| 596 | check_op();
|
|---|
| 597 | for (i = 0; i < 100000; i++)
|
|---|
| 598 | check_sqrt(pattern(0, P_Rno, P_R));
|
|---|
| 599 | for (i = 0; i < 100; i++)
|
|---|
| 600 | check_sqrt(pattern(0, P_Z, P_R));
|
|---|
| 601 | check_sqrt(pattern(0,P_Z,P_Z1));
|
|---|
| 602 |
|
|---|
| 603 | printf("%d errors.\n", nerrors);
|
|---|
| 604 | return nerrors == 0 ? 0 : 1;
|
|---|
| 605 | }
|
|---|