Skip to content

Commit cd21e58

Browse files
committedJan 13, 2014
Make lgamma and friends work, add test.
We can't use weak aliases on variables in emscripten, so get rid of __signgam and just use signgam.
1 parent b167b3c commit cd21e58

File tree

8 files changed

+141
-11
lines changed

8 files changed

+141
-11
lines changed
 
+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#include <math.h>
22

3-
extern int __signgam;
3+
extern int signgam;
44
double __lgamma_r(double, int *);
55

66
double lgamma(double x)
77
{
8-
return __lgamma_r(x, &__signgam);
8+
return __lgamma_r(x, &signgam);
99
}
+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#include <math.h>
22

3-
extern int __signgam;
3+
extern int signgam;
44
float __lgammaf_r(float, int *);
55

66
float lgammaf(float x)
77
{
8-
return __lgammaf_r(x, &__signgam);
8+
return __lgammaf_r(x, &signgam);
99
}

‎system/lib/libc/musl/src/math/lgammal.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -376,11 +376,11 @@ long double __lgammal_r(long double x, int *sg) {
376376
}
377377
#endif
378378

379-
extern int __signgam;
379+
extern int signgam;
380380

381381
long double lgammal(long double x)
382382
{
383-
return __lgammal_r(x, &__signgam);
383+
return __lgammal_r(x, &signgam);
384384
}
385385

386386
weak_alias(__lgammal_r, lgammal_r);
+1-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
#include <math.h>
22
#include "libc.h"
33

4-
int __signgam = 0;
5-
6-
weak_alias(__signgam, signgam);
4+
int signgam = 0;

‎system/lib/libcextra.symbols

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
T __lgammaf_r
66
T __lgammal_r
77
T __memrchr
8-
D __signgam
98
T __sindf
109
T __strchrnul
1110
T __strxfrm_l
@@ -73,7 +72,7 @@
7372
T regerror
7473
T regexec
7574
T regfree
76-
W signgam
75+
D signgam
7776
T strcasecmp_l
7877
T strcasestr
7978
W strchrnul

‎tests/math/lgamma.in

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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+
}

‎tests/math/lgamma.out

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-8.03528,-1
2+
2.24181,1
3+
-10.2138,-1
4+
-6.44641,-1
5+
11.1804,1
6+
0.309354,1
7+
1.3084,-1
8+
0.459903,1
9+
0.177784,1
10+
1.41155,-1
11+
inf,1
12+
0,1
13+
inf,1
14+
0,1
15+
inf,1
16+
inf,1
17+
inf,1
18+
nan,1

‎tests/test_core.py

+10
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,15 @@ def test_math_hyperbolic(self):
837837
expected = open(path_from_root('tests', 'hyperbolic', 'output.txt'), 'r').read()
838838
self.do_run(src, expected)
839839

840+
def test_math_lgamma(self):
841+
if self.emcc_args is None: return self.skip('requires emcc')
842+
if not self.is_le32(): return self.skip('le32 needed for accurate math')
843+
844+
test_path = path_from_root('tests', 'math', 'lgamma')
845+
src, output = (test_path + s for s in ('.in', '.out'))
846+
847+
self.do_run_from_file(src, output)
848+
840849
def test_frexp(self):
841850
test_path = path_from_root('tests', 'core', 'test_frexp')
842851
src, output = (test_path + s for s in ('.in', '.out'))
@@ -1289,6 +1298,7 @@ def test_exception_2(self):
12891298

12901299
self.do_run_from_file(src, output)
12911300

1301+
12921302
def test_white_list_exception(self):
12931303
if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
12941304

0 commit comments

Comments
 (0)