|
| 1 | +#define _BSD_SOURCE 1 |
| 2 | +#define _XOPEN_SOURCE 700 |
| 3 | +#include <stdint.h> |
| 4 | +#include <stdio.h> |
| 5 | +#include <fenv.h> |
| 6 | +#include <float.h> |
| 7 | +#include <math.h> |
| 8 | + |
| 9 | +#define RN 0 |
| 10 | +#define T(...) {__FILE__, __LINE__, __VA_ARGS__}, |
| 11 | +#define POS const char *file; int line; |
| 12 | +struct f_fi {POS int r; float x; float y; float dy; long long i; int e; }; |
| 13 | + |
| 14 | +#define DIVBYZERO 0 |
| 15 | +#define INEXACT 0 |
| 16 | +#define INVALID 0 |
| 17 | +#define OVERFLOW 0 |
| 18 | +#define UNDERFLOW 0 |
| 19 | + |
| 20 | +#define inf INFINITY |
| 21 | +#define nan NAN |
| 22 | + |
| 23 | +static struct f_fi t[] = { |
| 24 | +T(RN, -0x1.02239f3c6a8f1p+3, -0x1.0120f61b63d5ep+3, 0x1.89ccc4p-6, -1, INEXACT) |
| 25 | +T(RN, 0x1.161868e18bc67p+2, 0x1.1ef3b263fd60bp+1, -0x1.6d0264p-3, 1, INEXACT) |
| 26 | +T(RN, -0x1.0c34b3e01e6e7p+3, -0x1.46d73255263d9p+3, 0x1.e0ec76p-3, -1, INEXACT) |
| 27 | +T(RN, -0x1.a206f0a19dcc4p+2, -0x1.9c91f19ac48c5p+2, 0x1.c2a38cp-2, -1, INEXACT) |
| 28 | +T(RN, 0x1.288bbb0d6a1e6p+3, 0x1.65c60768fcc11p+3, 0x1.2f22c2p-2, 1, INEXACT) |
| 29 | +T(RN, 0x1.52efd0cd80497p-1, 0x1.3cc760be720b3p-2, 0x1.0527e2p-2, 1, INEXACT) |
| 30 | +T(RN, -0x1.a05cc754481d1p-2, 0x1.4ef387fea1014p+0, -0x1.c3b036p-2, -1, INEXACT) |
| 31 | +T(RN, 0x1.1f9ef934745cbp-1, 0x1.d6f0efacc5699p-2, 0x1.c0b0a8p-2, 1, INEXACT) |
| 32 | +T(RN, 0x1.8c5db097f7442p-1, 0x1.6c1a14cf91533p-3, 0x1.16f4cap-5, 1, INEXACT) |
| 33 | +T(RN, -0x1.5b86ea8118a0ep-1, 0x1.695b1e0a0a59ep+0, 0x1.ada69ep-2, -1, INEXACT) |
| 34 | +T(RN, 0x0p+0, inf, 0x0p+0, 1, DIVBYZERO) |
| 35 | +/* T(RN, -0x0p+0, inf, 0x0p+0, -1, DIVBYZERO) This one fails in native as well */ |
| 36 | +T(RN, 0x1p+0, 0x0p+0, 0x0p+0, 1, 0) |
| 37 | +T(RN, -0x1p+0, inf, 0x0p+0, 1, DIVBYZERO) |
| 38 | +T(RN, 0x1p+1, 0x0p+0, 0x0p+0, 1, 0) |
| 39 | +T(RN, -0x1p+1, inf, 0x0p+0, 1, DIVBYZERO) |
| 40 | +T(RN, inf, inf, 0x0p+0, 1, 0) |
| 41 | +T(RN, -inf, inf, 0x0p+0, -1, 0) |
| 42 | +T(RN, nan, nan, 0x0p+0, 1, 0) |
| 43 | +}; |
| 44 | + |
| 45 | +static int eulpf(float x) |
| 46 | +{ |
| 47 | + union { float f; uint32_t i; } u = { x }; |
| 48 | + int e = u.i>>23 & 0xff; |
| 49 | + |
| 50 | + if (!e) |
| 51 | + e++; |
| 52 | + return e - 0x7f - 23; |
| 53 | +} |
| 54 | + |
| 55 | +static int checkulp(float d, int r) |
| 56 | +{ |
| 57 | + // TODO: we only care about >=1.5 ulp errors for now, should be 1.0 |
| 58 | + if (r == RN) |
| 59 | + return fabsf(d) < 1.5; |
| 60 | + return 1; |
| 61 | +} |
| 62 | + |
| 63 | +static float ulperrf(float got, float want, float dwant) |
| 64 | +{ |
| 65 | + if (isnan(got) && isnan(want)) |
| 66 | + return 0; |
| 67 | + if (got == want) { |
| 68 | + if (signbit(got) == signbit(want)) |
| 69 | + return dwant; |
| 70 | + return INFINITY; |
| 71 | + } |
| 72 | + if (isinf(got)) { |
| 73 | + got = copysignf(0x1p127, got); |
| 74 | + want *= 0.5; |
| 75 | + } |
| 76 | + return scalbn(got - want, -eulpf(want)) + dwant; |
| 77 | +} |
| 78 | + |
| 79 | +int main(void) |
| 80 | +{ |
| 81 | + int yi; |
| 82 | + double y; |
| 83 | + float d; |
| 84 | + int e, i, err = 0; |
| 85 | + struct f_fi *p; |
| 86 | + |
| 87 | + for (i = 0; i < sizeof t/sizeof *t; i++) { |
| 88 | + p = t + i; |
| 89 | + |
| 90 | + if (p->r < 0) |
| 91 | + continue; |
| 92 | + y = lgammaf(p->x); |
| 93 | + yi = signgam; |
| 94 | + |
| 95 | + printf("%g,%d\n", y, yi); |
| 96 | + |
| 97 | + d = ulperrf(y, p->y, p->dy); |
| 98 | + if (!checkulp(d, p->r) || (!isnan(p->x) && p->x!=-inf && !(p->e&DIVBYZERO) && yi != p->i)) { |
| 99 | + /* printf("%s:%d: %d lgammaf(%g) want %g,%lld got %g,%d ulperr %.3f = %g + %g\n", |
| 100 | + p->file, p->line, p->r, p->x, p->y, p->i, y, yi, d, d-p->dy, p->dy); */ |
| 101 | + err++; |
| 102 | + } |
| 103 | + } |
| 104 | + return !!err; |
| 105 | +} |
0 commit comments