2 * ULP error checking tool for math functions.
4 * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 * See https://llvm.org/LICENSE.txt for license information.
6 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
19 /* Don't depend on mpfr by default. */
28 /* Enable the build of vector math code. */
32 static inline uint64_t
54 static inline uint32_t
76 static uint64_t seed
= 0x0123456789abcdef;
80 seed
= 6364136223846793005ull * seed
+ 1;
81 return seed
^ (seed
>> 32);
84 /* Uniform random in [0,n]. */
137 /* result = y + tail*2^ulpexp. */
156 static inline uint64_t
157 next1 (struct gen
*g
)
159 /* For single argument use randomized incremental steps,
160 that produce dense sampling without collisions and allow
161 testing all inputs in a range. */
162 uint64_t r
= g
->start
+ g
->off
;
163 g
->off
+= g
->step
+ randn (g
->step
/ 2);
165 g
->off
-= g
->len
; /* hack. */
169 static inline uint64_t
170 next2 (uint64_t *x2
, struct gen
*g
)
172 /* For two arguments use uniform random sampling. */
173 uint64_t r
= g
->start
+ randn (g
->len
);
174 *x2
= g
->start2
+ randn (g
->len2
);
178 static struct args_f1
181 return (struct args_f1
){asfloat (next1 (g
))};
184 static struct args_f2
188 uint64_t x
= next2 (&x2
, g
);
189 return (struct args_f2
){asfloat (x
), asfloat (x2
)};
192 static struct args_d1
195 return (struct args_d1
){asdouble (next1 (g
))};
198 static struct args_d2
202 uint64_t x
= next2 (&x2
, g
);
203 return (struct args_d2
){asdouble (x
), asdouble (x2
)};
213 unsigned long long n
;
218 /* Wrappers for sincos. */
219 static float sincosf_sinf(float x
) {(void)cosf(x
); return sinf(x
);}
220 static float sincosf_cosf(float x
) {(void)sinf(x
); return cosf(x
);}
221 static double sincos_sin(double x
) {(void)cos(x
); return sin(x
);}
222 static double sincos_cos(double x
) {(void)sin(x
); return cos(x
);}
224 static int sincos_mpfr_sin(mpfr_t y
, const mpfr_t x
, mpfr_rnd_t r
) { mpfr_cos(y
,x
,r
); return mpfr_sin(y
,x
,r
); }
225 static int sincos_mpfr_cos(mpfr_t y
, const mpfr_t x
, mpfr_rnd_t r
) { mpfr_sin(y
,x
,r
); return mpfr_cos(y
,x
,r
); }
228 /* A bit of a hack: call vector functions twice with the same
229 input in lane 0 but a different value in other lanes: once
230 with an in-range value and then with a special case value. */
231 static int secondcall
;
233 /* Wrappers for vector functions. */
234 #if __aarch64__ && WANT_VMATH
235 typedef __f32x4_t v_float
;
236 typedef __f64x2_t v_double
;
237 static const float fv
[2] = {1.0f
, -INFINITY
};
238 static const double dv
[2] = {1.0, -INFINITY
};
239 static inline v_float
argf(float x
) { return (v_float
){x
,x
,x
,fv
[secondcall
]}; }
240 static inline v_double
argd(double x
) { return (v_double
){x
,dv
[secondcall
]}; }
242 static float v_sinf(float x
) { return __v_sinf(argf(x
))[0]; }
243 static float v_cosf(float x
) { return __v_cosf(argf(x
))[0]; }
244 static float v_expf_1u(float x
) { return __v_expf_1u(argf(x
))[0]; }
245 static float v_expf(float x
) { return __v_expf(argf(x
))[0]; }
246 static float v_exp2f_1u(float x
) { return __v_exp2f_1u(argf(x
))[0]; }
247 static float v_exp2f(float x
) { return __v_exp2f(argf(x
))[0]; }
248 static float v_logf(float x
) { return __v_logf(argf(x
))[0]; }
249 static float v_powf(float x
, float y
) { return __v_powf(argf(x
),argf(y
))[0]; }
250 static double v_sin(double x
) { return __v_sin(argd(x
))[0]; }
251 static double v_cos(double x
) { return __v_cos(argd(x
))[0]; }
252 static double v_exp(double x
) { return __v_exp(argd(x
))[0]; }
253 static double v_log(double x
) { return __v_log(argd(x
))[0]; }
254 static double v_pow(double x
, double y
) { return __v_pow(argd(x
),argd(y
))[0]; }
256 static float vn_sinf(float x
) { return __vn_sinf(argf(x
))[0]; }
257 static float vn_cosf(float x
) { return __vn_cosf(argf(x
))[0]; }
258 static float vn_expf_1u(float x
) { return __vn_expf_1u(argf(x
))[0]; }
259 static float vn_expf(float x
) { return __vn_expf(argf(x
))[0]; }
260 static float vn_exp2f_1u(float x
) { return __vn_exp2f_1u(argf(x
))[0]; }
261 static float vn_exp2f(float x
) { return __vn_exp2f(argf(x
))[0]; }
262 static float vn_logf(float x
) { return __vn_logf(argf(x
))[0]; }
263 static float vn_powf(float x
, float y
) { return __vn_powf(argf(x
),argf(y
))[0]; }
264 static double vn_sin(double x
) { return __vn_sin(argd(x
))[0]; }
265 static double vn_cos(double x
) { return __vn_cos(argd(x
))[0]; }
266 static double vn_exp(double x
) { return __vn_exp(argd(x
))[0]; }
267 static double vn_log(double x
) { return __vn_log(argd(x
))[0]; }
268 static double vn_pow(double x
, double y
) { return __vn_pow(argd(x
),argd(y
))[0]; }
269 static float Z_sinf(float x
) { return _ZGVnN4v_sinf(argf(x
))[0]; }
270 static float Z_cosf(float x
) { return _ZGVnN4v_cosf(argf(x
))[0]; }
271 static float Z_expf(float x
) { return _ZGVnN4v_expf(argf(x
))[0]; }
272 static float Z_exp2f(float x
) { return _ZGVnN4v_exp2f(argf(x
))[0]; }
273 static float Z_logf(float x
) { return _ZGVnN4v_logf(argf(x
))[0]; }
274 static float Z_powf(float x
, float y
) { return _ZGVnN4vv_powf(argf(x
),argf(y
))[0]; }
275 static double Z_sin(double x
) { return _ZGVnN2v_sin(argd(x
))[0]; }
276 static double Z_cos(double x
) { return _ZGVnN2v_cos(argd(x
))[0]; }
277 static double Z_exp(double x
) { return _ZGVnN2v_exp(argd(x
))[0]; }
278 static double Z_log(double x
) { return _ZGVnN2v_log(argd(x
))[0]; }
279 static double Z_pow(double x
, double y
) { return _ZGVnN2vv_pow(argd(x
),argd(y
))[0]; }
292 float (*f2
) (float, float);
293 double (*d1
) (double);
294 double (*d2
) (double, double);
298 double (*f1
) (double);
299 double (*f2
) (double, double);
300 long double (*d1
) (long double);
301 long double (*d2
) (long double, long double);
306 int (*f1
) (mpfr_t
, const mpfr_t
, mpfr_rnd_t
);
307 int (*f2
) (mpfr_t
, const mpfr_t
, const mpfr_t
, mpfr_rnd_t
);
308 int (*d1
) (mpfr_t
, const mpfr_t
, mpfr_rnd_t
);
309 int (*d2
) (mpfr_t
, const mpfr_t
, const mpfr_t
, mpfr_rnd_t
);
314 static const struct fun fun
[] = {
316 # define F(x, x_wrap, x_long, x_mpfr, a, s, t, twice) \
317 {#x, a, s, twice, {.t = x_wrap}, {.t = x_long}, {.t = x_mpfr}},
319 # define F(x, x_wrap, x_long, x_mpfr, a, s, t, twice) \
320 {#x, a, s, twice, {.t = x_wrap}, {.t = x_long}},
322 #define F1(x) F (x##f, x##f, x, mpfr_##x, 1, 1, f1, 0)
323 #define F2(x) F (x##f, x##f, x, mpfr_##x, 2, 1, f2, 0)
324 #define D1(x) F (x, x, x##l, mpfr_##x, 1, 0, d1, 0)
325 #define D2(x) F (x, x, x##l, mpfr_##x, 2, 0, d2, 0)
328 F (sincosf_sinf
, sincosf_sinf
, sincos_sin
, sincos_mpfr_sin
, 1, 1, f1
, 0)
329 F (sincosf_cosf
, sincosf_cosf
, sincos_cos
, sincos_mpfr_cos
, 1, 1, f1
, 0)
341 F (__s_sinf
, __s_sinf
, sin
, mpfr_sin
, 1, 1, f1
, 0)
342 F (__s_cosf
, __s_cosf
, cos
, mpfr_cos
, 1, 1, f1
, 0)
343 F (__s_expf_1u
, __s_expf_1u
, exp
, mpfr_exp
, 1, 1, f1
, 0)
344 F (__s_expf
, __s_expf
, exp
, mpfr_exp
, 1, 1, f1
, 0)
345 F (__s_exp2f_1u
, __s_exp2f_1u
, exp2
, mpfr_exp2
, 1, 1, f1
, 0)
346 F (__s_exp2f
, __s_exp2f
, exp2
, mpfr_exp2
, 1, 1, f1
, 0)
347 F (__s_powf
, __s_powf
, pow
, mpfr_pow
, 2, 1, f2
, 0)
348 F (__s_logf
, __s_logf
, log
, mpfr_log
, 1, 1, f1
, 0)
349 F (__s_sin
, __s_sin
, sinl
, mpfr_sin
, 1, 0, d1
, 0)
350 F (__s_cos
, __s_cos
, cosl
, mpfr_cos
, 1, 0, d1
, 0)
351 F (__s_exp
, __s_exp
, expl
, mpfr_exp
, 1, 0, d1
, 0)
352 F (__s_log
, __s_log
, logl
, mpfr_log
, 1, 0, d1
, 0)
353 F (__s_pow
, __s_pow
, powl
, mpfr_pow
, 2, 0, d2
, 0)
355 F (__v_sinf
, v_sinf
, sin
, mpfr_sin
, 1, 1, f1
, 1)
356 F (__v_cosf
, v_cosf
, cos
, mpfr_cos
, 1, 1, f1
, 1)
357 F (__v_expf_1u
, v_expf_1u
, exp
, mpfr_exp
, 1, 1, f1
, 1)
358 F (__v_expf
, v_expf
, exp
, mpfr_exp
, 1, 1, f1
, 1)
359 F (__v_exp2f_1u
, v_exp2f_1u
, exp2
, mpfr_exp2
, 1, 1, f1
, 1)
360 F (__v_exp2f
, v_exp2f
, exp2
, mpfr_exp2
, 1, 1, f1
, 1)
361 F (__v_logf
, v_logf
, log
, mpfr_log
, 1, 1, f1
, 1)
362 F (__v_powf
, v_powf
, pow
, mpfr_pow
, 2, 1, f2
, 1)
363 F (__v_sin
, v_sin
, sinl
, mpfr_sin
, 1, 0, d1
, 1)
364 F (__v_cos
, v_cos
, cosl
, mpfr_cos
, 1, 0, d1
, 1)
365 F (__v_exp
, v_exp
, expl
, mpfr_exp
, 1, 0, d1
, 1)
366 F (__v_log
, v_log
, logl
, mpfr_log
, 1, 0, d1
, 1)
367 F (__v_pow
, v_pow
, powl
, mpfr_pow
, 2, 0, d2
, 1)
369 F (__vn_sinf
, vn_sinf
, sin
, mpfr_sin
, 1, 1, f1
, 1)
370 F (__vn_cosf
, vn_cosf
, cos
, mpfr_cos
, 1, 1, f1
, 1)
371 F (__vn_expf_1u
, vn_expf_1u
, exp
, mpfr_exp
, 1, 1, f1
, 1)
372 F (__vn_expf
, vn_expf
, exp
, mpfr_exp
, 1, 1, f1
, 1)
373 F (__vn_exp2f_1u
, vn_exp2f_1u
, exp2
, mpfr_exp2
, 1, 1, f1
, 1)
374 F (__vn_exp2f
, vn_exp2f
, exp2
, mpfr_exp2
, 1, 1, f1
, 1)
375 F (__vn_logf
, vn_logf
, log
, mpfr_log
, 1, 1, f1
, 1)
376 F (__vn_powf
, vn_powf
, pow
, mpfr_pow
, 2, 1, f2
, 1)
377 F (__vn_sin
, vn_sin
, sinl
, mpfr_sin
, 1, 0, d1
, 1)
378 F (__vn_cos
, vn_cos
, cosl
, mpfr_cos
, 1, 0, d1
, 1)
379 F (__vn_exp
, vn_exp
, expl
, mpfr_exp
, 1, 0, d1
, 1)
380 F (__vn_log
, vn_log
, logl
, mpfr_log
, 1, 0, d1
, 1)
381 F (__vn_pow
, vn_pow
, powl
, mpfr_pow
, 2, 0, d2
, 1)
382 F (_ZGVnN4v_sinf
, Z_sinf
, sin
, mpfr_sin
, 1, 1, f1
, 1)
383 F (_ZGVnN4v_cosf
, Z_cosf
, cos
, mpfr_cos
, 1, 1, f1
, 1)
384 F (_ZGVnN4v_expf
, Z_expf
, exp
, mpfr_exp
, 1, 1, f1
, 1)
385 F (_ZGVnN4v_exp2f
, Z_exp2f
, exp2
, mpfr_exp2
, 1, 1, f1
, 1)
386 F (_ZGVnN4v_logf
, Z_logf
, log
, mpfr_log
, 1, 1, f1
, 1)
387 F (_ZGVnN4vv_powf
, Z_powf
, pow
, mpfr_pow
, 2, 1, f2
, 1)
388 F (_ZGVnN2v_sin
, Z_sin
, sinl
, mpfr_sin
, 1, 0, d1
, 1)
389 F (_ZGVnN2v_cos
, Z_cos
, cosl
, mpfr_cos
, 1, 0, d1
, 1)
390 F (_ZGVnN2v_exp
, Z_exp
, expl
, mpfr_exp
, 1, 0, d1
, 1)
391 F (_ZGVnN2v_log
, Z_log
, logl
, mpfr_log
, 1, 0, d1
, 1)
392 F (_ZGVnN2vv_pow
, Z_pow
, powl
, mpfr_pow
, 2, 0, d2
, 1)
403 /* Boilerplate for generic calls. */
408 int e
= asuint (x
) >> 23 & 0xff;
411 return e
- 0x7f - 23;
414 ulpscale_d (double x
)
416 int e
= asuint64 (x
) >> 52 & 0x7ff;
419 return e
- 0x3ff - 52;
422 call_f1 (const struct fun
*f
, struct args_f1 a
)
424 return f
->fun
.f1 (a
.x
);
427 call_f2 (const struct fun
*f
, struct args_f2 a
)
429 return f
->fun
.f2 (a
.x
, a
.x2
);
433 call_d1 (const struct fun
*f
, struct args_d1 a
)
435 return f
->fun
.d1 (a
.x
);
438 call_d2 (const struct fun
*f
, struct args_d2 a
)
440 return f
->fun
.d2 (a
.x
, a
.x2
);
443 call_long_f1 (const struct fun
*f
, struct args_f1 a
)
445 return f
->fun_long
.f1 (a
.x
);
448 call_long_f2 (const struct fun
*f
, struct args_f2 a
)
450 return f
->fun_long
.f2 (a
.x
, a
.x2
);
452 static inline long double
453 call_long_d1 (const struct fun
*f
, struct args_d1 a
)
455 return f
->fun_long
.d1 (a
.x
);
457 static inline long double
458 call_long_d2 (const struct fun
*f
, struct args_d2 a
)
460 return f
->fun_long
.d2 (a
.x
, a
.x2
);
463 printcall_f1 (const struct fun
*f
, struct args_f1 a
)
465 printf ("%s(%a)", f
->name
, a
.x
);
468 printcall_f2 (const struct fun
*f
, struct args_f2 a
)
470 printf ("%s(%a, %a)", f
->name
, a
.x
, a
.x2
);
473 printcall_d1 (const struct fun
*f
, struct args_d1 a
)
475 printf ("%s(%a)", f
->name
, a
.x
);
478 printcall_d2 (const struct fun
*f
, struct args_d2 a
)
480 printf ("%s(%a, %a)", f
->name
, a
.x
, a
.x2
);
483 printgen_f1 (const struct fun
*f
, struct gen
*gen
)
485 printf ("%s in [%a;%a]", f
->name
, asfloat (gen
->start
),
486 asfloat (gen
->start
+ gen
->len
));
489 printgen_f2 (const struct fun
*f
, struct gen
*gen
)
491 printf ("%s in [%a;%a] x [%a;%a]", f
->name
, asfloat (gen
->start
),
492 asfloat (gen
->start
+ gen
->len
), asfloat (gen
->start2
),
493 asfloat (gen
->start2
+ gen
->len2
));
496 printgen_d1 (const struct fun
*f
, struct gen
*gen
)
498 printf ("%s in [%a;%a]", f
->name
, asdouble (gen
->start
),
499 asdouble (gen
->start
+ gen
->len
));
502 printgen_d2 (const struct fun
*f
, struct gen
*gen
)
504 printf ("%s in [%a;%a] x [%a;%a]", f
->name
, asdouble (gen
->start
),
505 asdouble (gen
->start
+ gen
->len
), asdouble (gen
->start2
),
506 asdouble (gen
->start2
+ gen
->len2
));
509 #define reduce_f1(a, f, op) (f (a.x))
510 #define reduce_f2(a, f, op) (f (a.x) op f (a.x2))
511 #define reduce_d1(a, f, op) (f (a.x))
512 #define reduce_d2(a, f, op) (f (a.x) op f (a.x2))
514 #ifndef IEEE_754_2008_SNAN
515 # define IEEE_754_2008_SNAN 1
518 issignaling_f (float x
)
520 uint32_t ix
= asuint (x
);
521 if (!IEEE_754_2008_SNAN
)
522 return (ix
& 0x7fc00000) == 0x7fc00000;
523 return 2 * (ix
^ 0x00400000) > 2u * 0x7fc00000;
526 issignaling_d (double x
)
528 uint64_t ix
= asuint64 (x
);
529 if (!IEEE_754_2008_SNAN
)
530 return (ix
& 0x7ff8000000000000) == 0x7ff8000000000000;
531 return 2 * (ix
^ 0x0008000000000000) > 2 * 0x7ff8000000000000ULL
;
552 #define prec_mpfr_f 50
553 #define prec_mpfr_d 80
561 call_mpfr_f1 (mpfr_t y
, const struct fun
*f
, struct args_f1 a
, mpfr_rnd_t r
)
563 MPFR_DECL_INIT (x
, prec_f
);
564 mpfr_set_flt (x
, a
.x
, MPFR_RNDN
);
565 return f
->fun_mpfr
.f1 (y
, x
, r
);
568 call_mpfr_f2 (mpfr_t y
, const struct fun
*f
, struct args_f2 a
, mpfr_rnd_t r
)
570 MPFR_DECL_INIT (x
, prec_f
);
571 MPFR_DECL_INIT (x2
, prec_f
);
572 mpfr_set_flt (x
, a
.x
, MPFR_RNDN
);
573 mpfr_set_flt (x2
, a
.x2
, MPFR_RNDN
);
574 return f
->fun_mpfr
.f2 (y
, x
, x2
, r
);
577 call_mpfr_d1 (mpfr_t y
, const struct fun
*f
, struct args_d1 a
, mpfr_rnd_t r
)
579 MPFR_DECL_INIT (x
, prec_d
);
580 mpfr_set_d (x
, a
.x
, MPFR_RNDN
);
581 return f
->fun_mpfr
.d1 (y
, x
, r
);
584 call_mpfr_d2 (mpfr_t y
, const struct fun
*f
, struct args_d2 a
, mpfr_rnd_t r
)
586 MPFR_DECL_INIT (x
, prec_d
);
587 MPFR_DECL_INIT (x2
, prec_d
);
588 mpfr_set_d (x
, a
.x
, MPFR_RNDN
);
589 mpfr_set_d (x2
, a
.x2
, MPFR_RNDN
);
590 return f
->fun_mpfr
.d2 (y
, x
, x2
, r
);
594 #define float_f float
595 #define double_f double
596 #define copysign_f copysignf
597 #define nextafter_f nextafterf
599 #define asuint_f asuint
600 #define asfloat_f asfloat
601 #define scalbn_f scalbnf
602 #define lscalbn_f scalbn
603 #define halfinf_f 0x1p127f
604 #define min_normal_f 0x1p-126f
606 #define float_d double
607 #define double_d long double
608 #define copysign_d copysign
609 #define nextafter_d nextafter
611 #define asuint_d asuint64
612 #define asfloat_d asdouble
613 #define scalbn_d scalbn
614 #define lscalbn_d scalbnl
615 #define halfinf_d 0x1p1023
616 #define min_normal_d 0x1p-1022
641 puts ("./ulp [-q] [-m] [-f] [-r nudz] [-l soft-ulplimit] [-e ulplimit] func "
642 "lo [hi [x lo2 hi2] [count]]");
643 puts ("Compares func against a higher precision implementation in [lo; hi].");
645 puts ("-m: use mpfr even if faster method is available.");
646 puts ("-f: disable fenv testing (rounding modes and exceptions).");
647 puts ("Supported func:");
648 for (const struct fun
*f
= fun
; f
->name
; f
++)
649 printf ("\t%s\n", f
->name
);
654 cmp (const struct fun
*f
, struct gen
*gen
, const struct conf
*conf
)
657 if (f
->arity
== 1 && f
->singleprec
)
658 r
= cmp_f1 (f
, gen
, conf
);
659 else if (f
->arity
== 2 && f
->singleprec
)
660 r
= cmp_f2 (f
, gen
, conf
);
661 else if (f
->arity
== 1 && !f
->singleprec
)
662 r
= cmp_d1 (f
, gen
, conf
);
663 else if (f
->arity
== 2 && !f
->singleprec
)
664 r
= cmp_d2 (f
, gen
, conf
);
671 getnum (const char *s
, int singleprec
)
679 else if (s
[0] == '-')
681 sign
= singleprec
? 1ULL << 31 : 1ULL << 63;
684 /* 0xXXXX is treated as bit representation, '-' flips the sign bit. */
685 if (s
[0] == '0' && tolower (s
[1]) == 'x' && strchr (s
, 'p') == 0)
686 return sign
^ strtoull (s
, 0, 0);
687 // /* SNaN, QNaN, NaN, Inf. */
688 // for (i=0; s[i] && i < sizeof buf; i++)
689 // buf[i] = tolower(s[i]);
691 // if (strcmp(buf, "snan") == 0)
692 // return sign | (singleprec ? 0x7fa00000 : 0x7ff4000000000000);
693 // if (strcmp(buf, "qnan") == 0 || strcmp(buf, "nan") == 0)
694 // return sign | (singleprec ? 0x7fc00000 : 0x7ff8000000000000);
695 // if (strcmp(buf, "inf") == 0 || strcmp(buf, "infinity") == 0)
696 // return sign | (singleprec ? 0x7f800000 : 0x7ff0000000000000);
697 /* Otherwise assume it's a floating-point literal. */
699 | (singleprec
? asuint (strtof (s
, 0)) : asuint64 (strtod (s
, 0)));
703 parsegen (struct gen
*g
, int argc
, char *argv
[], const struct fun
*f
)
705 int singleprec
= f
->singleprec
;
706 int arity
= f
->arity
;
707 uint64_t a
, b
, a2
, b2
, n
;
710 b
= a
= getnum (argv
[0], singleprec
);
712 if (argc
> 1 && strcmp (argv
[1], "x") == 0)
719 b
= getnum (argv
[1], singleprec
);
720 if (argc
> 2 && strcmp (argv
[2], "x") == 0)
726 b2
= a2
= getnum (argv
[0], singleprec
);
728 b2
= getnum (argv
[1], singleprec
);
730 n
= strtoull (argv
[2], 0, 0);
733 //printf("ab %lx %lx ab2 %lx %lx n %lu\n", a, b, a2, b2, n);
741 g
->step
= n
? (g
->len
+ 1) / n
: 1;
742 g
->start2
= g
->len2
= 0;
749 g
->off
= g
->step
= 0;
759 main (int argc
, char *argv
[])
769 conf
.errlim
= INFINITY
;
776 if (argv
[0][0] != '-')
785 conf
.errlim
= strtod (argv
[0], 0);
795 conf
.softlim
= strtod (argv
[0], 0);
804 conf
.rc
= argv
[0][2];
811 conf
.rc
= argv
[0][0];
821 conf
.r
= FE_TONEAREST
;
827 conf
.r
= FE_DOWNWARD
;
830 conf
.r
= FE_TOWARDZERO
;
835 for (f
= fun
; f
->name
; f
++)
836 if (strcmp (argv
[0], f
->name
) == 0)
840 if (!f
->singleprec
&& LDBL_MANT_DIG
== DBL_MANT_DIG
)
841 conf
.mpfr
= 1; /* Use mpfr if long double has no extra precision. */
842 if (!USE_MPFR
&& conf
.mpfr
)
844 puts ("mpfr is not available.");
849 parsegen (&gen
, argc
, argv
, f
);
851 return cmp (f
, &gen
, &conf
);