xref: /freebsd-src/contrib/arm-optimized-routines/math/test/ulp.c (revision 072a4ba82a01476eaee33781ccd241033eefcf0b)
131914882SAlex Richardson /*
231914882SAlex Richardson  * ULP error checking tool for math functions.
331914882SAlex Richardson  *
4*072a4ba8SAndrew Turner  * Copyright (c) 2019-2022, Arm Limited.
5*072a4ba8SAndrew Turner  * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
631914882SAlex Richardson  */
731914882SAlex Richardson 
831914882SAlex Richardson #include <ctype.h>
931914882SAlex Richardson #include <fenv.h>
1031914882SAlex Richardson #include <float.h>
1131914882SAlex Richardson #include <math.h>
1231914882SAlex Richardson #include <stdint.h>
1331914882SAlex Richardson #include <stdio.h>
1431914882SAlex Richardson #include <stdlib.h>
1531914882SAlex Richardson #include <string.h>
1631914882SAlex Richardson #include "mathlib.h"
1731914882SAlex Richardson 
1831914882SAlex Richardson /* Don't depend on mpfr by default.  */
1931914882SAlex Richardson #ifndef USE_MPFR
2031914882SAlex Richardson # define USE_MPFR 0
2131914882SAlex Richardson #endif
2231914882SAlex Richardson #if USE_MPFR
2331914882SAlex Richardson # include <mpfr.h>
2431914882SAlex Richardson #endif
2531914882SAlex Richardson 
2631914882SAlex Richardson #ifndef WANT_VMATH
2731914882SAlex Richardson /* Enable the build of vector math code.  */
2831914882SAlex Richardson # define WANT_VMATH 1
2931914882SAlex Richardson #endif
3031914882SAlex Richardson 
3131914882SAlex Richardson static inline uint64_t
3231914882SAlex Richardson asuint64 (double f)
3331914882SAlex Richardson {
3431914882SAlex Richardson   union
3531914882SAlex Richardson   {
3631914882SAlex Richardson     double f;
3731914882SAlex Richardson     uint64_t i;
3831914882SAlex Richardson   } u = {f};
3931914882SAlex Richardson   return u.i;
4031914882SAlex Richardson }
4131914882SAlex Richardson 
4231914882SAlex Richardson static inline double
4331914882SAlex Richardson asdouble (uint64_t i)
4431914882SAlex Richardson {
4531914882SAlex Richardson   union
4631914882SAlex Richardson   {
4731914882SAlex Richardson     uint64_t i;
4831914882SAlex Richardson     double f;
4931914882SAlex Richardson   } u = {i};
5031914882SAlex Richardson   return u.f;
5131914882SAlex Richardson }
5231914882SAlex Richardson 
5331914882SAlex Richardson static inline uint32_t
5431914882SAlex Richardson asuint (float f)
5531914882SAlex Richardson {
5631914882SAlex Richardson   union
5731914882SAlex Richardson   {
5831914882SAlex Richardson     float f;
5931914882SAlex Richardson     uint32_t i;
6031914882SAlex Richardson   } u = {f};
6131914882SAlex Richardson   return u.i;
6231914882SAlex Richardson }
6331914882SAlex Richardson 
6431914882SAlex Richardson static inline float
6531914882SAlex Richardson asfloat (uint32_t i)
6631914882SAlex Richardson {
6731914882SAlex Richardson   union
6831914882SAlex Richardson   {
6931914882SAlex Richardson     uint32_t i;
7031914882SAlex Richardson     float f;
7131914882SAlex Richardson   } u = {i};
7231914882SAlex Richardson   return u.f;
7331914882SAlex Richardson }
7431914882SAlex Richardson 
7531914882SAlex Richardson static uint64_t seed = 0x0123456789abcdef;
7631914882SAlex Richardson static uint64_t
7731914882SAlex Richardson rand64 (void)
7831914882SAlex Richardson {
7931914882SAlex Richardson   seed = 6364136223846793005ull * seed + 1;
8031914882SAlex Richardson   return seed ^ (seed >> 32);
8131914882SAlex Richardson }
8231914882SAlex Richardson 
8331914882SAlex Richardson /* Uniform random in [0,n].  */
8431914882SAlex Richardson static uint64_t
8531914882SAlex Richardson randn (uint64_t n)
8631914882SAlex Richardson {
8731914882SAlex Richardson   uint64_t r, m;
8831914882SAlex Richardson 
8931914882SAlex Richardson   if (n == 0)
9031914882SAlex Richardson     return 0;
9131914882SAlex Richardson   n++;
9231914882SAlex Richardson   if (n == 0)
9331914882SAlex Richardson     return rand64 ();
9431914882SAlex Richardson   for (;;)
9531914882SAlex Richardson     {
9631914882SAlex Richardson       r = rand64 ();
9731914882SAlex Richardson       m = r % n;
9831914882SAlex Richardson       if (r - m <= -n)
9931914882SAlex Richardson 	return m;
10031914882SAlex Richardson     }
10131914882SAlex Richardson }
10231914882SAlex Richardson 
10331914882SAlex Richardson struct gen
10431914882SAlex Richardson {
10531914882SAlex Richardson   uint64_t start;
10631914882SAlex Richardson   uint64_t len;
10731914882SAlex Richardson   uint64_t start2;
10831914882SAlex Richardson   uint64_t len2;
10931914882SAlex Richardson   uint64_t off;
11031914882SAlex Richardson   uint64_t step;
11131914882SAlex Richardson   uint64_t cnt;
11231914882SAlex Richardson };
11331914882SAlex Richardson 
11431914882SAlex Richardson struct args_f1
11531914882SAlex Richardson {
11631914882SAlex Richardson   float x;
11731914882SAlex Richardson };
11831914882SAlex Richardson 
11931914882SAlex Richardson struct args_f2
12031914882SAlex Richardson {
12131914882SAlex Richardson   float x;
12231914882SAlex Richardson   float x2;
12331914882SAlex Richardson };
12431914882SAlex Richardson 
12531914882SAlex Richardson struct args_d1
12631914882SAlex Richardson {
12731914882SAlex Richardson   double x;
12831914882SAlex Richardson };
12931914882SAlex Richardson 
13031914882SAlex Richardson struct args_d2
13131914882SAlex Richardson {
13231914882SAlex Richardson   double x;
13331914882SAlex Richardson   double x2;
13431914882SAlex Richardson };
13531914882SAlex Richardson 
13631914882SAlex Richardson /* result = y + tail*2^ulpexp.  */
13731914882SAlex Richardson struct ret_f
13831914882SAlex Richardson {
13931914882SAlex Richardson   float y;
14031914882SAlex Richardson   double tail;
14131914882SAlex Richardson   int ulpexp;
14231914882SAlex Richardson   int ex;
14331914882SAlex Richardson   int ex_may;
14431914882SAlex Richardson };
14531914882SAlex Richardson 
14631914882SAlex Richardson struct ret_d
14731914882SAlex Richardson {
14831914882SAlex Richardson   double y;
14931914882SAlex Richardson   double tail;
15031914882SAlex Richardson   int ulpexp;
15131914882SAlex Richardson   int ex;
15231914882SAlex Richardson   int ex_may;
15331914882SAlex Richardson };
15431914882SAlex Richardson 
15531914882SAlex Richardson static inline uint64_t
15631914882SAlex Richardson next1 (struct gen *g)
15731914882SAlex Richardson {
15831914882SAlex Richardson   /* For single argument use randomized incremental steps,
15931914882SAlex Richardson      that produce dense sampling without collisions and allow
16031914882SAlex Richardson      testing all inputs in a range.  */
16131914882SAlex Richardson   uint64_t r = g->start + g->off;
16231914882SAlex Richardson   g->off += g->step + randn (g->step / 2);
16331914882SAlex Richardson   if (g->off > g->len)
16431914882SAlex Richardson     g->off -= g->len; /* hack.  */
16531914882SAlex Richardson   return r;
16631914882SAlex Richardson }
16731914882SAlex Richardson 
16831914882SAlex Richardson static inline uint64_t
16931914882SAlex Richardson next2 (uint64_t *x2, struct gen *g)
17031914882SAlex Richardson {
17131914882SAlex Richardson   /* For two arguments use uniform random sampling.  */
17231914882SAlex Richardson   uint64_t r = g->start + randn (g->len);
17331914882SAlex Richardson   *x2 = g->start2 + randn (g->len2);
17431914882SAlex Richardson   return r;
17531914882SAlex Richardson }
17631914882SAlex Richardson 
17731914882SAlex Richardson static struct args_f1
17831914882SAlex Richardson next_f1 (void *g)
17931914882SAlex Richardson {
18031914882SAlex Richardson   return (struct args_f1){asfloat (next1 (g))};
18131914882SAlex Richardson }
18231914882SAlex Richardson 
18331914882SAlex Richardson static struct args_f2
18431914882SAlex Richardson next_f2 (void *g)
18531914882SAlex Richardson {
18631914882SAlex Richardson   uint64_t x2;
18731914882SAlex Richardson   uint64_t x = next2 (&x2, g);
18831914882SAlex Richardson   return (struct args_f2){asfloat (x), asfloat (x2)};
18931914882SAlex Richardson }
19031914882SAlex Richardson 
19131914882SAlex Richardson static struct args_d1
19231914882SAlex Richardson next_d1 (void *g)
19331914882SAlex Richardson {
19431914882SAlex Richardson   return (struct args_d1){asdouble (next1 (g))};
19531914882SAlex Richardson }
19631914882SAlex Richardson 
19731914882SAlex Richardson static struct args_d2
19831914882SAlex Richardson next_d2 (void *g)
19931914882SAlex Richardson {
20031914882SAlex Richardson   uint64_t x2;
20131914882SAlex Richardson   uint64_t x = next2 (&x2, g);
20231914882SAlex Richardson   return (struct args_d2){asdouble (x), asdouble (x2)};
20331914882SAlex Richardson }
20431914882SAlex Richardson 
20531914882SAlex Richardson struct conf
20631914882SAlex Richardson {
20731914882SAlex Richardson   int r;
20831914882SAlex Richardson   int rc;
20931914882SAlex Richardson   int quiet;
21031914882SAlex Richardson   int mpfr;
21131914882SAlex Richardson   int fenv;
21231914882SAlex Richardson   unsigned long long n;
21331914882SAlex Richardson   double softlim;
21431914882SAlex Richardson   double errlim;
21531914882SAlex Richardson };
21631914882SAlex Richardson 
21731914882SAlex Richardson /* A bit of a hack: call vector functions twice with the same
21831914882SAlex Richardson    input in lane 0 but a different value in other lanes: once
21931914882SAlex Richardson    with an in-range value and then with a special case value.  */
22031914882SAlex Richardson static int secondcall;
22131914882SAlex Richardson 
22231914882SAlex Richardson /* Wrappers for vector functions.  */
22331914882SAlex Richardson #if __aarch64__ && WANT_VMATH
22431914882SAlex Richardson typedef __f32x4_t v_float;
22531914882SAlex Richardson typedef __f64x2_t v_double;
226*072a4ba8SAndrew Turner /* First element of fv and dv may be changed by -c argument.  */
227*072a4ba8SAndrew Turner static float fv[2] = {1.0f, -INFINITY};
228*072a4ba8SAndrew Turner static double dv[2] = {1.0, -INFINITY};
22931914882SAlex Richardson static inline v_float argf(float x) { return (v_float){x,x,x,fv[secondcall]}; }
23031914882SAlex Richardson static inline v_double argd(double x) { return (v_double){x,dv[secondcall]}; }
231*072a4ba8SAndrew Turner #if WANT_SVE_MATH
232*072a4ba8SAndrew Turner #include <arm_sve.h>
233*072a4ba8SAndrew Turner typedef __SVFloat32_t sv_float;
234*072a4ba8SAndrew Turner typedef __SVFloat64_t sv_double;
23531914882SAlex Richardson 
236*072a4ba8SAndrew Turner static inline sv_float svargf(float x)  {
237*072a4ba8SAndrew Turner 	int n = svcntw();
238*072a4ba8SAndrew Turner 	float base[n];
239*072a4ba8SAndrew Turner 	for (int i=0; i<n; i++)
240*072a4ba8SAndrew Turner 		base[i] = (float)x;
241*072a4ba8SAndrew Turner 	base[n-1] = (float) fv[secondcall];
242*072a4ba8SAndrew Turner 	return svld1(svptrue_b32(), base);
243*072a4ba8SAndrew Turner }
244*072a4ba8SAndrew Turner static inline sv_double svargd(double x) {
245*072a4ba8SAndrew Turner 	int n = svcntd();
246*072a4ba8SAndrew Turner 	double base[n];
247*072a4ba8SAndrew Turner 	for (int i=0; i<n; i++)
248*072a4ba8SAndrew Turner 		base[i] = x;
249*072a4ba8SAndrew Turner 	base[n-1] = dv[secondcall];
250*072a4ba8SAndrew Turner 	return svld1(svptrue_b64(), base);
251*072a4ba8SAndrew Turner }
252*072a4ba8SAndrew Turner static inline float svretf(sv_float vec)  {
253*072a4ba8SAndrew Turner 	int n = svcntw();
254*072a4ba8SAndrew Turner 	float res[n];
255*072a4ba8SAndrew Turner 	svst1(svptrue_b32(), res, vec);
256*072a4ba8SAndrew Turner 	return res[0];
257*072a4ba8SAndrew Turner }
258*072a4ba8SAndrew Turner static inline double svretd(sv_double vec) {
259*072a4ba8SAndrew Turner 	int n = svcntd();
260*072a4ba8SAndrew Turner 	double res[n];
261*072a4ba8SAndrew Turner 	svst1(svptrue_b64(), res, vec);
262*072a4ba8SAndrew Turner 	return res[0];
263*072a4ba8SAndrew Turner }
26431914882SAlex Richardson #endif
26531914882SAlex Richardson #endif
26631914882SAlex Richardson 
267*072a4ba8SAndrew Turner #if WANT_SVE_MATH
268*072a4ba8SAndrew Turner long double
269*072a4ba8SAndrew Turner dummyl (long double x)
270*072a4ba8SAndrew Turner {
271*072a4ba8SAndrew Turner   return x;
272*072a4ba8SAndrew Turner }
273*072a4ba8SAndrew Turner 
274*072a4ba8SAndrew Turner double
275*072a4ba8SAndrew Turner dummy (double x)
276*072a4ba8SAndrew Turner {
277*072a4ba8SAndrew Turner   return x;
278*072a4ba8SAndrew Turner }
279*072a4ba8SAndrew Turner 
280*072a4ba8SAndrew Turner static sv_double
281*072a4ba8SAndrew Turner __sv_dummy (sv_double x)
282*072a4ba8SAndrew Turner {
283*072a4ba8SAndrew Turner   return x;
284*072a4ba8SAndrew Turner }
285*072a4ba8SAndrew Turner 
286*072a4ba8SAndrew Turner static sv_float
287*072a4ba8SAndrew Turner __sv_dummyf (sv_float x)
288*072a4ba8SAndrew Turner {
289*072a4ba8SAndrew Turner   return x;
290*072a4ba8SAndrew Turner }
291*072a4ba8SAndrew Turner #endif
292*072a4ba8SAndrew Turner 
293*072a4ba8SAndrew Turner #include "test/ulp_wrappers.h"
294*072a4ba8SAndrew Turner 
295*072a4ba8SAndrew Turner /* Wrappers for SVE functions.  */
296*072a4ba8SAndrew Turner #if WANT_SVE_MATH
297*072a4ba8SAndrew Turner static double sv_dummy (double x) { return svretd (__sv_dummy (svargd (x))); }
298*072a4ba8SAndrew Turner static float sv_dummyf (float x) { return svretf (__sv_dummyf (svargf (x))); }
299*072a4ba8SAndrew Turner #endif
300*072a4ba8SAndrew Turner 
30131914882SAlex Richardson struct fun
30231914882SAlex Richardson {
30331914882SAlex Richardson   const char *name;
30431914882SAlex Richardson   int arity;
30531914882SAlex Richardson   int singleprec;
30631914882SAlex Richardson   int twice;
30731914882SAlex Richardson   union
30831914882SAlex Richardson   {
30931914882SAlex Richardson     float (*f1) (float);
31031914882SAlex Richardson     float (*f2) (float, float);
31131914882SAlex Richardson     double (*d1) (double);
31231914882SAlex Richardson     double (*d2) (double, double);
31331914882SAlex Richardson   } fun;
31431914882SAlex Richardson   union
31531914882SAlex Richardson   {
31631914882SAlex Richardson     double (*f1) (double);
31731914882SAlex Richardson     double (*f2) (double, double);
31831914882SAlex Richardson     long double (*d1) (long double);
31931914882SAlex Richardson     long double (*d2) (long double, long double);
32031914882SAlex Richardson   } fun_long;
32131914882SAlex Richardson #if USE_MPFR
32231914882SAlex Richardson   union
32331914882SAlex Richardson   {
32431914882SAlex Richardson     int (*f1) (mpfr_t, const mpfr_t, mpfr_rnd_t);
32531914882SAlex Richardson     int (*f2) (mpfr_t, const mpfr_t, const mpfr_t, mpfr_rnd_t);
32631914882SAlex Richardson     int (*d1) (mpfr_t, const mpfr_t, mpfr_rnd_t);
32731914882SAlex Richardson     int (*d2) (mpfr_t, const mpfr_t, const mpfr_t, mpfr_rnd_t);
32831914882SAlex Richardson   } fun_mpfr;
32931914882SAlex Richardson #endif
33031914882SAlex Richardson };
33131914882SAlex Richardson 
33231914882SAlex Richardson static const struct fun fun[] = {
33331914882SAlex Richardson #if USE_MPFR
33431914882SAlex Richardson # define F(x, x_wrap, x_long, x_mpfr, a, s, t, twice) \
33531914882SAlex Richardson   {#x, a, s, twice, {.t = x_wrap}, {.t = x_long}, {.t = x_mpfr}},
33631914882SAlex Richardson #else
33731914882SAlex Richardson # define F(x, x_wrap, x_long, x_mpfr, a, s, t, twice) \
33831914882SAlex Richardson   {#x, a, s, twice, {.t = x_wrap}, {.t = x_long}},
33931914882SAlex Richardson #endif
34031914882SAlex Richardson #define F1(x) F (x##f, x##f, x, mpfr_##x, 1, 1, f1, 0)
34131914882SAlex Richardson #define F2(x) F (x##f, x##f, x, mpfr_##x, 2, 1, f2, 0)
34231914882SAlex Richardson #define D1(x) F (x, x, x##l, mpfr_##x, 1, 0, d1, 0)
34331914882SAlex Richardson #define D2(x) F (x, x, x##l, mpfr_##x, 2, 0, d2, 0)
344*072a4ba8SAndrew Turner /* Neon routines.  */
345*072a4ba8SAndrew Turner #define VF1(x) F (__v_##x##f, v_##x##f, x, mpfr_##x, 1, 1, f1, 0)
346*072a4ba8SAndrew Turner #define VF2(x) F (__v_##x##f, v_##x##f, x, mpfr_##x, 2, 1, f2, 0)
347*072a4ba8SAndrew Turner #define VD1(x) F (__v_##x, v_##x, x##l, mpfr_##x, 1, 0, d1, 0)
348*072a4ba8SAndrew Turner #define VD2(x) F (__v_##x, v_##x, x##l, mpfr_##x, 2, 0, d2, 0)
349*072a4ba8SAndrew Turner #define VNF1(x) F (__vn_##x##f, vn_##x##f, x, mpfr_##x, 1, 1, f1, 0)
350*072a4ba8SAndrew Turner #define VNF2(x) F (__vn_##x##f, vn_##x##f, x, mpfr_##x, 2, 1, f2, 0)
351*072a4ba8SAndrew Turner #define VND1(x) F (__vn_##x, vn_##x, x##l, mpfr_##x, 1, 0, d1, 0)
352*072a4ba8SAndrew Turner #define VND2(x) F (__vn_##x, vn_##x, x##l, mpfr_##x, 2, 0, d2, 0)
353*072a4ba8SAndrew Turner #define ZVF1(x) F (_ZGVnN4v_##x##f, Z_##x##f, x, mpfr_##x, 1, 1, f1, 0)
354*072a4ba8SAndrew Turner #define ZVF2(x) F (_ZGVnN4vv_##x##f, Z_##x##f, x, mpfr_##x, 2, 1, f2, 0)
355*072a4ba8SAndrew Turner #define ZVD1(x) F (_ZGVnN2v_##x, Z_##x, x##l, mpfr_##x, 1, 0, d1, 0)
356*072a4ba8SAndrew Turner #define ZVD2(x) F (_ZGVnN2vv_##x, Z_##x, x##l, mpfr_##x, 2, 0, d2, 0)
357*072a4ba8SAndrew Turner #define ZVNF1(x) VNF1 (x) ZVF1 (x)
358*072a4ba8SAndrew Turner #define ZVNF2(x) VNF2 (x) ZVF2 (x)
359*072a4ba8SAndrew Turner #define ZVND1(x) VND1 (x) ZVD1 (x)
360*072a4ba8SAndrew Turner #define ZVND2(x) VND2 (x) ZVD2 (x)
361*072a4ba8SAndrew Turner #define SF1(x) F (__s_##x##f, __s_##x##f, x, mpfr_##x, 1, 1, f1, 0)
362*072a4ba8SAndrew Turner #define SF2(x) F (__s_##x##f, __s_##x##f, x, mpfr_##x, 2, 1, f2, 0)
363*072a4ba8SAndrew Turner #define SD1(x) F (__s_##x, __s_##x, x##l, mpfr_##x, 1, 0, d1, 0)
364*072a4ba8SAndrew Turner #define SD2(x) F (__s_##x, __s_##x, x##l, mpfr_##x, 2, 0, d2, 0)
365*072a4ba8SAndrew Turner /* SVE routines.  */
366*072a4ba8SAndrew Turner #define SVF1(x) F (__sv_##x##f, sv_##x##f, x, mpfr_##x, 1, 1, f1, 0)
367*072a4ba8SAndrew Turner #define SVF2(x) F (__sv_##x##f, sv_##x##f, x, mpfr_##x, 2, 1, f2, 0)
368*072a4ba8SAndrew Turner #define SVD1(x) F (__sv_##x, sv_##x, x##l, mpfr_##x, 1, 0, d1, 0)
369*072a4ba8SAndrew Turner #define SVD2(x) F (__sv_##x, sv_##x, x##l, mpfr_##x, 2, 0, d2, 0)
370*072a4ba8SAndrew Turner #define ZSVF1(x) F (_ZGVsMxv_##x##f, Z_sv_##x##f, x, mpfr_##x, 1, 1, f1, 0)
371*072a4ba8SAndrew Turner #define ZSVF2(x) F (_ZGVsMxvv_##x##f, Z_sv_##x##f, x, mpfr_##x, 2, 1, f2, 0)
372*072a4ba8SAndrew Turner #define ZSVD1(x) F (_ZGVsMxv_##x, Z_sv_##x, x##l, mpfr_##x, 1, 0, d1, 0)
373*072a4ba8SAndrew Turner #define ZSVD2(x) F (_ZGVsMxvv_##x, Z_sv_##x, x##l, mpfr_##x, 2, 0, d2, 0)
374*072a4ba8SAndrew Turner 
375*072a4ba8SAndrew Turner #include "test/ulp_funcs.h"
376*072a4ba8SAndrew Turner 
377*072a4ba8SAndrew Turner #if WANT_SVE_MATH
378*072a4ba8SAndrew Turner  SVD1 (dummy)
379*072a4ba8SAndrew Turner  SVF1 (dummy)
38031914882SAlex Richardson #endif
381*072a4ba8SAndrew Turner 
38231914882SAlex Richardson #undef F
38331914882SAlex Richardson #undef F1
38431914882SAlex Richardson #undef F2
38531914882SAlex Richardson #undef D1
38631914882SAlex Richardson #undef D2
387*072a4ba8SAndrew Turner #undef SVF1
388*072a4ba8SAndrew Turner #undef SVF2
389*072a4ba8SAndrew Turner #undef SVD1
390*072a4ba8SAndrew Turner #undef SVD2
39131914882SAlex Richardson  {0}};
39231914882SAlex Richardson 
39331914882SAlex Richardson /* Boilerplate for generic calls.  */
39431914882SAlex Richardson 
39531914882SAlex Richardson static inline int
39631914882SAlex Richardson ulpscale_f (float x)
39731914882SAlex Richardson {
39831914882SAlex Richardson   int e = asuint (x) >> 23 & 0xff;
39931914882SAlex Richardson   if (!e)
40031914882SAlex Richardson     e++;
40131914882SAlex Richardson   return e - 0x7f - 23;
40231914882SAlex Richardson }
40331914882SAlex Richardson static inline int
40431914882SAlex Richardson ulpscale_d (double x)
40531914882SAlex Richardson {
40631914882SAlex Richardson   int e = asuint64 (x) >> 52 & 0x7ff;
40731914882SAlex Richardson   if (!e)
40831914882SAlex Richardson     e++;
40931914882SAlex Richardson   return e - 0x3ff - 52;
41031914882SAlex Richardson }
41131914882SAlex Richardson static inline float
41231914882SAlex Richardson call_f1 (const struct fun *f, struct args_f1 a)
41331914882SAlex Richardson {
41431914882SAlex Richardson   return f->fun.f1 (a.x);
41531914882SAlex Richardson }
41631914882SAlex Richardson static inline float
41731914882SAlex Richardson call_f2 (const struct fun *f, struct args_f2 a)
41831914882SAlex Richardson {
41931914882SAlex Richardson   return f->fun.f2 (a.x, a.x2);
42031914882SAlex Richardson }
42131914882SAlex Richardson 
42231914882SAlex Richardson static inline double
42331914882SAlex Richardson call_d1 (const struct fun *f, struct args_d1 a)
42431914882SAlex Richardson {
42531914882SAlex Richardson   return f->fun.d1 (a.x);
42631914882SAlex Richardson }
42731914882SAlex Richardson static inline double
42831914882SAlex Richardson call_d2 (const struct fun *f, struct args_d2 a)
42931914882SAlex Richardson {
43031914882SAlex Richardson   return f->fun.d2 (a.x, a.x2);
43131914882SAlex Richardson }
43231914882SAlex Richardson static inline double
43331914882SAlex Richardson call_long_f1 (const struct fun *f, struct args_f1 a)
43431914882SAlex Richardson {
43531914882SAlex Richardson   return f->fun_long.f1 (a.x);
43631914882SAlex Richardson }
43731914882SAlex Richardson static inline double
43831914882SAlex Richardson call_long_f2 (const struct fun *f, struct args_f2 a)
43931914882SAlex Richardson {
44031914882SAlex Richardson   return f->fun_long.f2 (a.x, a.x2);
44131914882SAlex Richardson }
44231914882SAlex Richardson static inline long double
44331914882SAlex Richardson call_long_d1 (const struct fun *f, struct args_d1 a)
44431914882SAlex Richardson {
44531914882SAlex Richardson   return f->fun_long.d1 (a.x);
44631914882SAlex Richardson }
44731914882SAlex Richardson static inline long double
44831914882SAlex Richardson call_long_d2 (const struct fun *f, struct args_d2 a)
44931914882SAlex Richardson {
45031914882SAlex Richardson   return f->fun_long.d2 (a.x, a.x2);
45131914882SAlex Richardson }
45231914882SAlex Richardson static inline void
45331914882SAlex Richardson printcall_f1 (const struct fun *f, struct args_f1 a)
45431914882SAlex Richardson {
45531914882SAlex Richardson   printf ("%s(%a)", f->name, a.x);
45631914882SAlex Richardson }
45731914882SAlex Richardson static inline void
45831914882SAlex Richardson printcall_f2 (const struct fun *f, struct args_f2 a)
45931914882SAlex Richardson {
46031914882SAlex Richardson   printf ("%s(%a, %a)", f->name, a.x, a.x2);
46131914882SAlex Richardson }
46231914882SAlex Richardson static inline void
46331914882SAlex Richardson printcall_d1 (const struct fun *f, struct args_d1 a)
46431914882SAlex Richardson {
46531914882SAlex Richardson   printf ("%s(%a)", f->name, a.x);
46631914882SAlex Richardson }
46731914882SAlex Richardson static inline void
46831914882SAlex Richardson printcall_d2 (const struct fun *f, struct args_d2 a)
46931914882SAlex Richardson {
47031914882SAlex Richardson   printf ("%s(%a, %a)", f->name, a.x, a.x2);
47131914882SAlex Richardson }
47231914882SAlex Richardson static inline void
47331914882SAlex Richardson printgen_f1 (const struct fun *f, struct gen *gen)
47431914882SAlex Richardson {
47531914882SAlex Richardson   printf ("%s in [%a;%a]", f->name, asfloat (gen->start),
47631914882SAlex Richardson 	  asfloat (gen->start + gen->len));
47731914882SAlex Richardson }
47831914882SAlex Richardson static inline void
47931914882SAlex Richardson printgen_f2 (const struct fun *f, struct gen *gen)
48031914882SAlex Richardson {
48131914882SAlex Richardson   printf ("%s in [%a;%a] x [%a;%a]", f->name, asfloat (gen->start),
48231914882SAlex Richardson 	  asfloat (gen->start + gen->len), asfloat (gen->start2),
48331914882SAlex Richardson 	  asfloat (gen->start2 + gen->len2));
48431914882SAlex Richardson }
48531914882SAlex Richardson static inline void
48631914882SAlex Richardson printgen_d1 (const struct fun *f, struct gen *gen)
48731914882SAlex Richardson {
48831914882SAlex Richardson   printf ("%s in [%a;%a]", f->name, asdouble (gen->start),
48931914882SAlex Richardson 	  asdouble (gen->start + gen->len));
49031914882SAlex Richardson }
49131914882SAlex Richardson static inline void
49231914882SAlex Richardson printgen_d2 (const struct fun *f, struct gen *gen)
49331914882SAlex Richardson {
49431914882SAlex Richardson   printf ("%s in [%a;%a] x [%a;%a]", f->name, asdouble (gen->start),
49531914882SAlex Richardson 	  asdouble (gen->start + gen->len), asdouble (gen->start2),
49631914882SAlex Richardson 	  asdouble (gen->start2 + gen->len2));
49731914882SAlex Richardson }
49831914882SAlex Richardson 
49931914882SAlex Richardson #define reduce_f1(a, f, op) (f (a.x))
50031914882SAlex Richardson #define reduce_f2(a, f, op) (f (a.x) op f (a.x2))
50131914882SAlex Richardson #define reduce_d1(a, f, op) (f (a.x))
50231914882SAlex Richardson #define reduce_d2(a, f, op) (f (a.x) op f (a.x2))
50331914882SAlex Richardson 
50431914882SAlex Richardson #ifndef IEEE_754_2008_SNAN
50531914882SAlex Richardson # define IEEE_754_2008_SNAN 1
50631914882SAlex Richardson #endif
50731914882SAlex Richardson static inline int
50831914882SAlex Richardson issignaling_f (float x)
50931914882SAlex Richardson {
51031914882SAlex Richardson   uint32_t ix = asuint (x);
51131914882SAlex Richardson   if (!IEEE_754_2008_SNAN)
51231914882SAlex Richardson     return (ix & 0x7fc00000) == 0x7fc00000;
51331914882SAlex Richardson   return 2 * (ix ^ 0x00400000) > 2u * 0x7fc00000;
51431914882SAlex Richardson }
51531914882SAlex Richardson static inline int
51631914882SAlex Richardson issignaling_d (double x)
51731914882SAlex Richardson {
51831914882SAlex Richardson   uint64_t ix = asuint64 (x);
51931914882SAlex Richardson   if (!IEEE_754_2008_SNAN)
52031914882SAlex Richardson     return (ix & 0x7ff8000000000000) == 0x7ff8000000000000;
52131914882SAlex Richardson   return 2 * (ix ^ 0x0008000000000000) > 2 * 0x7ff8000000000000ULL;
52231914882SAlex Richardson }
52331914882SAlex Richardson 
52431914882SAlex Richardson #if USE_MPFR
52531914882SAlex Richardson static mpfr_rnd_t
52631914882SAlex Richardson rmap (int r)
52731914882SAlex Richardson {
52831914882SAlex Richardson   switch (r)
52931914882SAlex Richardson     {
53031914882SAlex Richardson     case FE_TONEAREST:
53131914882SAlex Richardson       return MPFR_RNDN;
53231914882SAlex Richardson     case FE_TOWARDZERO:
53331914882SAlex Richardson       return MPFR_RNDZ;
53431914882SAlex Richardson     case FE_UPWARD:
53531914882SAlex Richardson       return MPFR_RNDU;
53631914882SAlex Richardson     case FE_DOWNWARD:
53731914882SAlex Richardson       return MPFR_RNDD;
53831914882SAlex Richardson     }
53931914882SAlex Richardson   return -1;
54031914882SAlex Richardson }
54131914882SAlex Richardson 
54231914882SAlex Richardson #define prec_mpfr_f 50
54331914882SAlex Richardson #define prec_mpfr_d 80
54431914882SAlex Richardson #define prec_f 24
54531914882SAlex Richardson #define prec_d 53
54631914882SAlex Richardson #define emin_f -148
54731914882SAlex Richardson #define emin_d -1073
54831914882SAlex Richardson #define emax_f 128
54931914882SAlex Richardson #define emax_d 1024
55031914882SAlex Richardson static inline int
55131914882SAlex Richardson call_mpfr_f1 (mpfr_t y, const struct fun *f, struct args_f1 a, mpfr_rnd_t r)
55231914882SAlex Richardson {
55331914882SAlex Richardson   MPFR_DECL_INIT (x, prec_f);
55431914882SAlex Richardson   mpfr_set_flt (x, a.x, MPFR_RNDN);
55531914882SAlex Richardson   return f->fun_mpfr.f1 (y, x, r);
55631914882SAlex Richardson }
55731914882SAlex Richardson static inline int
55831914882SAlex Richardson call_mpfr_f2 (mpfr_t y, const struct fun *f, struct args_f2 a, mpfr_rnd_t r)
55931914882SAlex Richardson {
56031914882SAlex Richardson   MPFR_DECL_INIT (x, prec_f);
56131914882SAlex Richardson   MPFR_DECL_INIT (x2, prec_f);
56231914882SAlex Richardson   mpfr_set_flt (x, a.x, MPFR_RNDN);
56331914882SAlex Richardson   mpfr_set_flt (x2, a.x2, MPFR_RNDN);
56431914882SAlex Richardson   return f->fun_mpfr.f2 (y, x, x2, r);
56531914882SAlex Richardson }
56631914882SAlex Richardson static inline int
56731914882SAlex Richardson call_mpfr_d1 (mpfr_t y, const struct fun *f, struct args_d1 a, mpfr_rnd_t r)
56831914882SAlex Richardson {
56931914882SAlex Richardson   MPFR_DECL_INIT (x, prec_d);
57031914882SAlex Richardson   mpfr_set_d (x, a.x, MPFR_RNDN);
57131914882SAlex Richardson   return f->fun_mpfr.d1 (y, x, r);
57231914882SAlex Richardson }
57331914882SAlex Richardson static inline int
57431914882SAlex Richardson call_mpfr_d2 (mpfr_t y, const struct fun *f, struct args_d2 a, mpfr_rnd_t r)
57531914882SAlex Richardson {
57631914882SAlex Richardson   MPFR_DECL_INIT (x, prec_d);
57731914882SAlex Richardson   MPFR_DECL_INIT (x2, prec_d);
57831914882SAlex Richardson   mpfr_set_d (x, a.x, MPFR_RNDN);
57931914882SAlex Richardson   mpfr_set_d (x2, a.x2, MPFR_RNDN);
58031914882SAlex Richardson   return f->fun_mpfr.d2 (y, x, x2, r);
58131914882SAlex Richardson }
58231914882SAlex Richardson #endif
58331914882SAlex Richardson 
58431914882SAlex Richardson #define float_f float
58531914882SAlex Richardson #define double_f double
58631914882SAlex Richardson #define copysign_f copysignf
58731914882SAlex Richardson #define nextafter_f nextafterf
58831914882SAlex Richardson #define fabs_f fabsf
58931914882SAlex Richardson #define asuint_f asuint
59031914882SAlex Richardson #define asfloat_f asfloat
59131914882SAlex Richardson #define scalbn_f scalbnf
59231914882SAlex Richardson #define lscalbn_f scalbn
59331914882SAlex Richardson #define halfinf_f 0x1p127f
59431914882SAlex Richardson #define min_normal_f 0x1p-126f
59531914882SAlex Richardson 
59631914882SAlex Richardson #define float_d double
59731914882SAlex Richardson #define double_d long double
59831914882SAlex Richardson #define copysign_d copysign
59931914882SAlex Richardson #define nextafter_d nextafter
60031914882SAlex Richardson #define fabs_d fabs
60131914882SAlex Richardson #define asuint_d asuint64
60231914882SAlex Richardson #define asfloat_d asdouble
60331914882SAlex Richardson #define scalbn_d scalbn
60431914882SAlex Richardson #define lscalbn_d scalbnl
60531914882SAlex Richardson #define halfinf_d 0x1p1023
60631914882SAlex Richardson #define min_normal_d 0x1p-1022
60731914882SAlex Richardson 
60831914882SAlex Richardson #define NEW_RT
60931914882SAlex Richardson #define RT(x) x##_f
61031914882SAlex Richardson #define T(x) x##_f1
61131914882SAlex Richardson #include "ulp.h"
61231914882SAlex Richardson #undef T
61331914882SAlex Richardson #define T(x) x##_f2
61431914882SAlex Richardson #include "ulp.h"
61531914882SAlex Richardson #undef T
61631914882SAlex Richardson #undef RT
61731914882SAlex Richardson 
61831914882SAlex Richardson #define NEW_RT
61931914882SAlex Richardson #define RT(x) x##_d
62031914882SAlex Richardson #define T(x) x##_d1
62131914882SAlex Richardson #include "ulp.h"
62231914882SAlex Richardson #undef T
62331914882SAlex Richardson #define T(x) x##_d2
62431914882SAlex Richardson #include "ulp.h"
62531914882SAlex Richardson #undef T
62631914882SAlex Richardson #undef RT
62731914882SAlex Richardson 
62831914882SAlex Richardson static void
62931914882SAlex Richardson usage (void)
63031914882SAlex Richardson {
63131914882SAlex Richardson   puts ("./ulp [-q] [-m] [-f] [-r nudz] [-l soft-ulplimit] [-e ulplimit] func "
63231914882SAlex Richardson 	"lo [hi [x lo2 hi2] [count]]");
63331914882SAlex Richardson   puts ("Compares func against a higher precision implementation in [lo; hi].");
63431914882SAlex Richardson   puts ("-q: quiet.");
63531914882SAlex Richardson   puts ("-m: use mpfr even if faster method is available.");
63631914882SAlex Richardson   puts ("-f: disable fenv testing (rounding modes and exceptions).");
637*072a4ba8SAndrew Turner #if __aarch64__ && WANT_VMATH
638*072a4ba8SAndrew Turner   puts ("-c: neutral 'control value' to test behaviour when one lane can affect another. \n"
639*072a4ba8SAndrew Turner 	"    This should be different from tested input in other lanes, and non-special \n"
640*072a4ba8SAndrew Turner 	"    (i.e. should not trigger fenv exceptions). Default is 1.");
641*072a4ba8SAndrew Turner #endif
64231914882SAlex Richardson   puts ("Supported func:");
64331914882SAlex Richardson   for (const struct fun *f = fun; f->name; f++)
64431914882SAlex Richardson     printf ("\t%s\n", f->name);
64531914882SAlex Richardson   exit (1);
64631914882SAlex Richardson }
64731914882SAlex Richardson 
64831914882SAlex Richardson static int
64931914882SAlex Richardson cmp (const struct fun *f, struct gen *gen, const struct conf *conf)
65031914882SAlex Richardson {
65131914882SAlex Richardson   int r = 1;
65231914882SAlex Richardson   if (f->arity == 1 && f->singleprec)
65331914882SAlex Richardson     r = cmp_f1 (f, gen, conf);
65431914882SAlex Richardson   else if (f->arity == 2 && f->singleprec)
65531914882SAlex Richardson     r = cmp_f2 (f, gen, conf);
65631914882SAlex Richardson   else if (f->arity == 1 && !f->singleprec)
65731914882SAlex Richardson     r = cmp_d1 (f, gen, conf);
65831914882SAlex Richardson   else if (f->arity == 2 && !f->singleprec)
65931914882SAlex Richardson     r = cmp_d2 (f, gen, conf);
66031914882SAlex Richardson   else
66131914882SAlex Richardson     usage ();
66231914882SAlex Richardson   return r;
66331914882SAlex Richardson }
66431914882SAlex Richardson 
66531914882SAlex Richardson static uint64_t
66631914882SAlex Richardson getnum (const char *s, int singleprec)
66731914882SAlex Richardson {
66831914882SAlex Richardson   //	int i;
66931914882SAlex Richardson   uint64_t sign = 0;
67031914882SAlex Richardson   //	char buf[12];
67131914882SAlex Richardson 
67231914882SAlex Richardson   if (s[0] == '+')
67331914882SAlex Richardson     s++;
67431914882SAlex Richardson   else if (s[0] == '-')
67531914882SAlex Richardson     {
67631914882SAlex Richardson       sign = singleprec ? 1ULL << 31 : 1ULL << 63;
67731914882SAlex Richardson       s++;
67831914882SAlex Richardson     }
67931914882SAlex Richardson   /* 0xXXXX is treated as bit representation, '-' flips the sign bit.  */
68031914882SAlex Richardson   if (s[0] == '0' && tolower (s[1]) == 'x' && strchr (s, 'p') == 0)
68131914882SAlex Richardson     return sign ^ strtoull (s, 0, 0);
68231914882SAlex Richardson   //	/* SNaN, QNaN, NaN, Inf.  */
68331914882SAlex Richardson   //	for (i=0; s[i] && i < sizeof buf; i++)
68431914882SAlex Richardson   //		buf[i] = tolower(s[i]);
68531914882SAlex Richardson   //	buf[i] = 0;
68631914882SAlex Richardson   //	if (strcmp(buf, "snan") == 0)
68731914882SAlex Richardson   //		return sign | (singleprec ? 0x7fa00000 : 0x7ff4000000000000);
68831914882SAlex Richardson   //	if (strcmp(buf, "qnan") == 0 || strcmp(buf, "nan") == 0)
68931914882SAlex Richardson   //		return sign | (singleprec ? 0x7fc00000 : 0x7ff8000000000000);
69031914882SAlex Richardson   //	if (strcmp(buf, "inf") == 0 || strcmp(buf, "infinity") == 0)
69131914882SAlex Richardson   //		return sign | (singleprec ? 0x7f800000 : 0x7ff0000000000000);
69231914882SAlex Richardson   /* Otherwise assume it's a floating-point literal.  */
69331914882SAlex Richardson   return sign
69431914882SAlex Richardson 	 | (singleprec ? asuint (strtof (s, 0)) : asuint64 (strtod (s, 0)));
69531914882SAlex Richardson }
69631914882SAlex Richardson 
69731914882SAlex Richardson static void
69831914882SAlex Richardson parsegen (struct gen *g, int argc, char *argv[], const struct fun *f)
69931914882SAlex Richardson {
70031914882SAlex Richardson   int singleprec = f->singleprec;
70131914882SAlex Richardson   int arity = f->arity;
70231914882SAlex Richardson   uint64_t a, b, a2, b2, n;
70331914882SAlex Richardson   if (argc < 1)
70431914882SAlex Richardson     usage ();
70531914882SAlex Richardson   b = a = getnum (argv[0], singleprec);
70631914882SAlex Richardson   n = 0;
70731914882SAlex Richardson   if (argc > 1 && strcmp (argv[1], "x") == 0)
70831914882SAlex Richardson     {
70931914882SAlex Richardson       argc -= 2;
71031914882SAlex Richardson       argv += 2;
71131914882SAlex Richardson     }
71231914882SAlex Richardson   else if (argc > 1)
71331914882SAlex Richardson     {
71431914882SAlex Richardson       b = getnum (argv[1], singleprec);
71531914882SAlex Richardson       if (argc > 2 && strcmp (argv[2], "x") == 0)
71631914882SAlex Richardson 	{
71731914882SAlex Richardson 	  argc -= 3;
71831914882SAlex Richardson 	  argv += 3;
71931914882SAlex Richardson 	}
72031914882SAlex Richardson     }
72131914882SAlex Richardson   b2 = a2 = getnum (argv[0], singleprec);
72231914882SAlex Richardson   if (argc > 1)
72331914882SAlex Richardson     b2 = getnum (argv[1], singleprec);
72431914882SAlex Richardson   if (argc > 2)
72531914882SAlex Richardson     n = strtoull (argv[2], 0, 0);
72631914882SAlex Richardson   if (argc > 3)
72731914882SAlex Richardson     usage ();
72831914882SAlex Richardson   //printf("ab %lx %lx ab2 %lx %lx n %lu\n", a, b, a2, b2, n);
72931914882SAlex Richardson   if (arity == 1)
73031914882SAlex Richardson     {
73131914882SAlex Richardson       g->start = a;
73231914882SAlex Richardson       g->len = b - a;
73331914882SAlex Richardson       if (n - 1 > b - a)
73431914882SAlex Richardson 	n = b - a + 1;
73531914882SAlex Richardson       g->off = 0;
73631914882SAlex Richardson       g->step = n ? (g->len + 1) / n : 1;
73731914882SAlex Richardson       g->start2 = g->len2 = 0;
73831914882SAlex Richardson       g->cnt = n;
73931914882SAlex Richardson     }
74031914882SAlex Richardson   else if (arity == 2)
74131914882SAlex Richardson     {
74231914882SAlex Richardson       g->start = a;
74331914882SAlex Richardson       g->len = b - a;
74431914882SAlex Richardson       g->off = g->step = 0;
74531914882SAlex Richardson       g->start2 = a2;
74631914882SAlex Richardson       g->len2 = b2 - a2;
74731914882SAlex Richardson       g->cnt = n;
74831914882SAlex Richardson     }
74931914882SAlex Richardson   else
75031914882SAlex Richardson     usage ();
75131914882SAlex Richardson }
75231914882SAlex Richardson 
75331914882SAlex Richardson int
75431914882SAlex Richardson main (int argc, char *argv[])
75531914882SAlex Richardson {
75631914882SAlex Richardson   const struct fun *f;
75731914882SAlex Richardson   struct gen gen;
75831914882SAlex Richardson   struct conf conf;
75931914882SAlex Richardson   conf.rc = 'n';
76031914882SAlex Richardson   conf.quiet = 0;
76131914882SAlex Richardson   conf.mpfr = 0;
76231914882SAlex Richardson   conf.fenv = 1;
76331914882SAlex Richardson   conf.softlim = 0;
76431914882SAlex Richardson   conf.errlim = INFINITY;
76531914882SAlex Richardson   for (;;)
76631914882SAlex Richardson     {
76731914882SAlex Richardson       argc--;
76831914882SAlex Richardson       argv++;
76931914882SAlex Richardson       if (argc < 1)
77031914882SAlex Richardson 	usage ();
77131914882SAlex Richardson       if (argv[0][0] != '-')
77231914882SAlex Richardson 	break;
77331914882SAlex Richardson       switch (argv[0][1])
77431914882SAlex Richardson 	{
77531914882SAlex Richardson 	case 'e':
77631914882SAlex Richardson 	  argc--;
77731914882SAlex Richardson 	  argv++;
77831914882SAlex Richardson 	  if (argc < 1)
77931914882SAlex Richardson 	    usage ();
78031914882SAlex Richardson 	  conf.errlim = strtod (argv[0], 0);
78131914882SAlex Richardson 	  break;
78231914882SAlex Richardson 	case 'f':
78331914882SAlex Richardson 	  conf.fenv = 0;
78431914882SAlex Richardson 	  break;
78531914882SAlex Richardson 	case 'l':
78631914882SAlex Richardson 	  argc--;
78731914882SAlex Richardson 	  argv++;
78831914882SAlex Richardson 	  if (argc < 1)
78931914882SAlex Richardson 	    usage ();
79031914882SAlex Richardson 	  conf.softlim = strtod (argv[0], 0);
79131914882SAlex Richardson 	  break;
79231914882SAlex Richardson 	case 'm':
79331914882SAlex Richardson 	  conf.mpfr = 1;
79431914882SAlex Richardson 	  break;
79531914882SAlex Richardson 	case 'q':
79631914882SAlex Richardson 	  conf.quiet = 1;
79731914882SAlex Richardson 	  break;
79831914882SAlex Richardson 	case 'r':
79931914882SAlex Richardson 	  conf.rc = argv[0][2];
80031914882SAlex Richardson 	  if (!conf.rc)
80131914882SAlex Richardson 	    {
80231914882SAlex Richardson 	      argc--;
80331914882SAlex Richardson 	      argv++;
80431914882SAlex Richardson 	      if (argc < 1)
80531914882SAlex Richardson 		usage ();
80631914882SAlex Richardson 	      conf.rc = argv[0][0];
80731914882SAlex Richardson 	    }
80831914882SAlex Richardson 	  break;
809*072a4ba8SAndrew Turner #if __aarch64__ && WANT_VMATH
810*072a4ba8SAndrew Turner 	case 'c':
811*072a4ba8SAndrew Turner 	  argc--;
812*072a4ba8SAndrew Turner 	  argv++;
813*072a4ba8SAndrew Turner 	  fv[0] = strtof(argv[0], 0);
814*072a4ba8SAndrew Turner 	  dv[0] = strtod(argv[0], 0);
815*072a4ba8SAndrew Turner 	  break;
816*072a4ba8SAndrew Turner #endif
81731914882SAlex Richardson 	default:
81831914882SAlex Richardson 	  usage ();
81931914882SAlex Richardson 	}
82031914882SAlex Richardson     }
82131914882SAlex Richardson   switch (conf.rc)
82231914882SAlex Richardson     {
82331914882SAlex Richardson     case 'n':
82431914882SAlex Richardson       conf.r = FE_TONEAREST;
82531914882SAlex Richardson       break;
82631914882SAlex Richardson     case 'u':
82731914882SAlex Richardson       conf.r = FE_UPWARD;
82831914882SAlex Richardson       break;
82931914882SAlex Richardson     case 'd':
83031914882SAlex Richardson       conf.r = FE_DOWNWARD;
83131914882SAlex Richardson       break;
83231914882SAlex Richardson     case 'z':
83331914882SAlex Richardson       conf.r = FE_TOWARDZERO;
83431914882SAlex Richardson       break;
83531914882SAlex Richardson     default:
83631914882SAlex Richardson       usage ();
83731914882SAlex Richardson     }
83831914882SAlex Richardson   for (f = fun; f->name; f++)
83931914882SAlex Richardson     if (strcmp (argv[0], f->name) == 0)
84031914882SAlex Richardson       break;
84131914882SAlex Richardson   if (!f->name)
84231914882SAlex Richardson     usage ();
84331914882SAlex Richardson   if (!f->singleprec && LDBL_MANT_DIG == DBL_MANT_DIG)
84431914882SAlex Richardson     conf.mpfr = 1; /* Use mpfr if long double has no extra precision.  */
84531914882SAlex Richardson   if (!USE_MPFR && conf.mpfr)
84631914882SAlex Richardson     {
84731914882SAlex Richardson       puts ("mpfr is not available.");
84831914882SAlex Richardson       return 0;
84931914882SAlex Richardson     }
85031914882SAlex Richardson   argc--;
85131914882SAlex Richardson   argv++;
85231914882SAlex Richardson   parsegen (&gen, argc, argv, f);
85331914882SAlex Richardson   conf.n = gen.cnt;
85431914882SAlex Richardson   return cmp (f, &gen, &conf);
85531914882SAlex Richardson }
856