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