1/* 2 * ULP error checking tool for math functions. 3 * 4 * Copyright (c) 2019-2023, Arm Limited. 5 * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception 6 */ 7 8#define _GNU_SOURCE 9#include <ctype.h> 10#include <fenv.h> 11#include <float.h> 12#include <math.h> 13#include <stdint.h> 14#include <stdio.h> 15#include <stdlib.h> 16#include <string.h> 17#include "mathlib.h" 18 19/* Don't depend on mpfr by default. */ 20#ifndef USE_MPFR 21# define USE_MPFR 0 22#endif 23#if USE_MPFR 24# include <mpfr.h> 25#endif 26 27static inline uint64_t 28asuint64 (double f) 29{ 30 union 31 { 32 double f; 33 uint64_t i; 34 } u = {f}; 35 return u.i; 36} 37 38static inline double 39asdouble (uint64_t i) 40{ 41 union 42 { 43 uint64_t i; 44 double f; 45 } u = {i}; 46 return u.f; 47} 48 49static inline uint32_t 50asuint (float f) 51{ 52 union 53 { 54 float f; 55 uint32_t i; 56 } u = {f}; 57 return u.i; 58} 59 60static inline float 61asfloat (uint32_t i) 62{ 63 union 64 { 65 uint32_t i; 66 float f; 67 } u = {i}; 68 return u.f; 69} 70 71static uint64_t seed = 0x0123456789abcdef; 72static uint64_t 73rand64 (void) 74{ 75 seed = 6364136223846793005ull * seed + 1; 76 return seed ^ (seed >> 32); 77} 78 79/* Uniform random in [0,n]. */ 80static uint64_t 81randn (uint64_t n) 82{ 83 uint64_t r, m; 84 85 if (n == 0) 86 return 0; 87 n++; 88 if (n == 0) 89 return rand64 (); 90 for (;;) 91 { 92 r = rand64 (); 93 m = r % n; 94 if (r - m <= -n) 95 return m; 96 } 97} 98 99struct gen 100{ 101 uint64_t start; 102 uint64_t len; 103 uint64_t start2; 104 uint64_t len2; 105 uint64_t off; 106 uint64_t step; 107 uint64_t cnt; 108}; 109 110struct args_f1 111{ 112 float x; 113}; 114 115struct args_f2 116{ 117 float x; 118 float x2; 119}; 120 121struct args_d1 122{ 123 double x; 124}; 125 126struct args_d2 127{ 128 double x; 129 double x2; 130}; 131 132/* result = y + tail*2^ulpexp. */ 133struct ret_f 134{ 135 float y; 136 double tail; 137 int ulpexp; 138 int ex; 139 int ex_may; 140}; 141 142struct ret_d 143{ 144 double y; 145 double tail; 146 int ulpexp; 147 int ex; 148 int ex_may; 149}; 150 151static inline uint64_t 152next1 (struct gen *g) 153{ 154 /* For single argument use randomized incremental steps, 155 that produce dense sampling without collisions and allow 156 testing all inputs in a range. */ 157 uint64_t r = g->start + g->off; 158 g->off += g->step + randn (g->step / 2); 159 if (g->off > g->len) 160 g->off -= g->len; /* hack. */ 161 return r; 162} 163 164static inline uint64_t 165next2 (uint64_t *x2, struct gen *g) 166{ 167 /* For two arguments use uniform random sampling. */ 168 uint64_t r = g->start + randn (g->len); 169 *x2 = g->start2 + randn (g->len2); 170 return r; 171} 172 173static struct args_f1 174next_f1 (void *g) 175{ 176 return (struct args_f1){asfloat (next1 (g))}; 177} 178 179static struct args_f2 180next_f2 (void *g) 181{ 182 uint64_t x2; 183 uint64_t x = next2 (&x2, g); 184 return (struct args_f2){asfloat (x), asfloat (x2)}; 185} 186 187static struct args_d1 188next_d1 (void *g) 189{ 190 return (struct args_d1){asdouble (next1 (g))}; 191} 192 193static struct args_d2 194next_d2 (void *g) 195{ 196 uint64_t x2; 197 uint64_t x = next2 (&x2, g); 198 return (struct args_d2){asdouble (x), asdouble (x2)}; 199} 200 201struct conf 202{ 203 int r; 204 int rc; 205 int quiet; 206 int mpfr; 207 int fenv; 208 unsigned long long n; 209 double softlim; 210 double errlim; 211 int ignore_zero_sign; 212}; 213 214/* A bit of a hack: call vector functions twice with the same 215 input in lane 0 but a different value in other lanes: once 216 with an in-range value and then with a special case value. */ 217static int secondcall; 218 219/* Wrappers for vector functions. */ 220#ifdef __vpcs 221typedef __f32x4_t v_float; 222typedef __f64x2_t v_double; 223/* First element of fv and dv may be changed by -c argument. */ 224static float fv[2] = {1.0f, -INFINITY}; 225static double dv[2] = {1.0, -INFINITY}; 226static inline v_float argf(float x) { return (v_float){x,x,x,fv[secondcall]}; } 227static inline v_double argd(double x) { return (v_double){x,dv[secondcall]}; } 228#if WANT_SVE_MATH 229#include <arm_sve.h> 230typedef __SVFloat32_t sv_float; 231typedef __SVFloat64_t sv_double; 232 233static inline sv_float svargf(float x) { 234 int n = svcntw(); 235 float base[n]; 236 for (int i=0; i<n; i++) 237 base[i] = (float)x; 238 base[n-1] = (float) fv[secondcall]; 239 return svld1(svptrue_b32(), base); 240} 241static inline sv_double svargd(double x) { 242 int n = svcntd(); 243 double base[n]; 244 for (int i=0; i<n; i++) 245 base[i] = x; 246 base[n-1] = dv[secondcall]; 247 return svld1(svptrue_b64(), base); 248} 249static inline float svretf(sv_float vec) { 250 int n = svcntw(); 251 float res[n]; 252 svst1(svptrue_b32(), res, vec); 253 return res[0]; 254} 255static inline double svretd(sv_double vec) { 256 int n = svcntd(); 257 double res[n]; 258 svst1(svptrue_b64(), res, vec); 259 return res[0]; 260} 261#endif 262#endif 263 264#include "test/ulp_wrappers.h" 265 266struct fun 267{ 268 const char *name; 269 int arity; 270 int singleprec; 271 int twice; 272 union 273 { 274 float (*f1) (float); 275 float (*f2) (float, float); 276 double (*d1) (double); 277 double (*d2) (double, double); 278 } fun; 279 union 280 { 281 double (*f1) (double); 282 double (*f2) (double, double); 283 long double (*d1) (long double); 284 long double (*d2) (long double, long double); 285 } fun_long; 286#if USE_MPFR 287 union 288 { 289 int (*f1) (mpfr_t, const mpfr_t, mpfr_rnd_t); 290 int (*f2) (mpfr_t, const mpfr_t, const mpfr_t, mpfr_rnd_t); 291 int (*d1) (mpfr_t, const mpfr_t, mpfr_rnd_t); 292 int (*d2) (mpfr_t, const mpfr_t, const mpfr_t, mpfr_rnd_t); 293 } fun_mpfr; 294#endif 295}; 296 297static const struct fun fun[] = { 298#if USE_MPFR 299# define F(x, x_wrap, x_long, x_mpfr, a, s, t, twice) \ 300 {#x, a, s, twice, {.t = x_wrap}, {.t = x_long}, {.t = x_mpfr}}, 301#else 302# define F(x, x_wrap, x_long, x_mpfr, a, s, t, twice) \ 303 {#x, a, s, twice, {.t = x_wrap}, {.t = x_long}}, 304#endif 305#define F1(x) F (x##f, x##f, x, mpfr_##x, 1, 1, f1, 0) 306#define F2(x) F (x##f, x##f, x, mpfr_##x, 2, 1, f2, 0) 307#define D1(x) F (x, x, x##l, mpfr_##x, 1, 0, d1, 0) 308#define D2(x) F (x, x, x##l, mpfr_##x, 2, 0, d2, 0) 309/* Neon routines. */ 310#define VF1(x) F (__v_##x##f, v_##x##f, x, mpfr_##x, 1, 1, f1, 0) 311#define VF2(x) F (__v_##x##f, v_##x##f, x, mpfr_##x, 2, 1, f2, 0) 312#define VD1(x) F (__v_##x, v_##x, x##l, mpfr_##x, 1, 0, d1, 0) 313#define VD2(x) F (__v_##x, v_##x, x##l, mpfr_##x, 2, 0, d2, 0) 314#define VNF1(x) F (__vn_##x##f, vn_##x##f, x, mpfr_##x, 1, 1, f1, 0) 315#define VNF2(x) F (__vn_##x##f, vn_##x##f, x, mpfr_##x, 2, 1, f2, 0) 316#define VND1(x) F (__vn_##x, vn_##x, x##l, mpfr_##x, 1, 0, d1, 0) 317#define VND2(x) F (__vn_##x, vn_##x, x##l, mpfr_##x, 2, 0, d2, 0) 318#define ZVF1(x) F (_ZGVnN4v_##x##f, Z_##x##f, x, mpfr_##x, 1, 1, f1, 0) 319#define ZVF2(x) F (_ZGVnN4vv_##x##f, Z_##x##f, x, mpfr_##x, 2, 1, f2, 0) 320#define ZVD1(x) F (_ZGVnN2v_##x, Z_##x, x##l, mpfr_##x, 1, 0, d1, 0) 321#define ZVD2(x) F (_ZGVnN2vv_##x, Z_##x, x##l, mpfr_##x, 2, 0, d2, 0) 322#define ZVNF1(x) VNF1 (x) ZVF1 (x) 323#define ZVNF2(x) VNF2 (x) ZVF2 (x) 324#define ZVND1(x) VND1 (x) ZVD1 (x) 325#define ZVND2(x) VND2 (x) ZVD2 (x) 326/* SVE routines. */ 327#define SVF1(x) F (__sv_##x##f, sv_##x##f, x, mpfr_##x, 1, 1, f1, 0) 328#define SVF2(x) F (__sv_##x##f, sv_##x##f, x, mpfr_##x, 2, 1, f2, 0) 329#define SVD1(x) F (__sv_##x, sv_##x, x##l, mpfr_##x, 1, 0, d1, 0) 330#define SVD2(x) F (__sv_##x, sv_##x, x##l, mpfr_##x, 2, 0, d2, 0) 331#define ZSVF1(x) F (_ZGVsMxv_##x##f, Z_sv_##x##f, x, mpfr_##x, 1, 1, f1, 0) 332#define ZSVF2(x) F (_ZGVsMxvv_##x##f, Z_sv_##x##f, x, mpfr_##x, 2, 1, f2, 0) 333#define ZSVD1(x) F (_ZGVsMxv_##x, Z_sv_##x, x##l, mpfr_##x, 1, 0, d1, 0) 334#define ZSVD2(x) F (_ZGVsMxvv_##x, Z_sv_##x, x##l, mpfr_##x, 2, 0, d2, 0) 335 336#include "test/ulp_funcs.h" 337 338#undef F 339#undef F1 340#undef F2 341#undef D1 342#undef D2 343#undef SVF1 344#undef SVF2 345#undef SVD1 346#undef SVD2 347 {0}}; 348 349/* Boilerplate for generic calls. */ 350 351static inline int 352ulpscale_f (float x) 353{ 354 int e = asuint (x) >> 23 & 0xff; 355 if (!e) 356 e++; 357 return e - 0x7f - 23; 358} 359static inline int 360ulpscale_d (double x) 361{ 362 int e = asuint64 (x) >> 52 & 0x7ff; 363 if (!e) 364 e++; 365 return e - 0x3ff - 52; 366} 367static inline float 368call_f1 (const struct fun *f, struct args_f1 a) 369{ 370 return f->fun.f1 (a.x); 371} 372static inline float 373call_f2 (const struct fun *f, struct args_f2 a) 374{ 375 return f->fun.f2 (a.x, a.x2); 376} 377 378static inline double 379call_d1 (const struct fun *f, struct args_d1 a) 380{ 381 return f->fun.d1 (a.x); 382} 383static inline double 384call_d2 (const struct fun *f, struct args_d2 a) 385{ 386 return f->fun.d2 (a.x, a.x2); 387} 388static inline double 389call_long_f1 (const struct fun *f, struct args_f1 a) 390{ 391 return f->fun_long.f1 (a.x); 392} 393static inline double 394call_long_f2 (const struct fun *f, struct args_f2 a) 395{ 396 return f->fun_long.f2 (a.x, a.x2); 397} 398static inline long double 399call_long_d1 (const struct fun *f, struct args_d1 a) 400{ 401 return f->fun_long.d1 (a.x); 402} 403static inline long double 404call_long_d2 (const struct fun *f, struct args_d2 a) 405{ 406 return f->fun_long.d2 (a.x, a.x2); 407} 408static inline void 409printcall_f1 (const struct fun *f, struct args_f1 a) 410{ 411 printf ("%s(%a)", f->name, a.x); 412} 413static inline void 414printcall_f2 (const struct fun *f, struct args_f2 a) 415{ 416 printf ("%s(%a, %a)", f->name, a.x, a.x2); 417} 418static inline void 419printcall_d1 (const struct fun *f, struct args_d1 a) 420{ 421 printf ("%s(%a)", f->name, a.x); 422} 423static inline void 424printcall_d2 (const struct fun *f, struct args_d2 a) 425{ 426 printf ("%s(%a, %a)", f->name, a.x, a.x2); 427} 428static inline void 429printgen_f1 (const struct fun *f, struct gen *gen) 430{ 431 printf ("%s in [%a;%a]", f->name, asfloat (gen->start), 432 asfloat (gen->start + gen->len)); 433} 434static inline void 435printgen_f2 (const struct fun *f, struct gen *gen) 436{ 437 printf ("%s in [%a;%a] x [%a;%a]", f->name, asfloat (gen->start), 438 asfloat (gen->start + gen->len), asfloat (gen->start2), 439 asfloat (gen->start2 + gen->len2)); 440} 441static inline void 442printgen_d1 (const struct fun *f, struct gen *gen) 443{ 444 printf ("%s in [%a;%a]", f->name, asdouble (gen->start), 445 asdouble (gen->start + gen->len)); 446} 447static inline void 448printgen_d2 (const struct fun *f, struct gen *gen) 449{ 450 printf ("%s in [%a;%a] x [%a;%a]", f->name, asdouble (gen->start), 451 asdouble (gen->start + gen->len), asdouble (gen->start2), 452 asdouble (gen->start2 + gen->len2)); 453} 454 455#define reduce_f1(a, f, op) (f (a.x)) 456#define reduce_f2(a, f, op) (f (a.x) op f (a.x2)) 457#define reduce_d1(a, f, op) (f (a.x)) 458#define reduce_d2(a, f, op) (f (a.x) op f (a.x2)) 459 460#ifndef IEEE_754_2008_SNAN 461# define IEEE_754_2008_SNAN 1 462#endif 463static inline int 464issignaling_f (float x) 465{ 466 uint32_t ix = asuint (x); 467 if (!IEEE_754_2008_SNAN) 468 return (ix & 0x7fc00000) == 0x7fc00000; 469 return 2 * (ix ^ 0x00400000) > 2u * 0x7fc00000; 470} 471static inline int 472issignaling_d (double x) 473{ 474 uint64_t ix = asuint64 (x); 475 if (!IEEE_754_2008_SNAN) 476 return (ix & 0x7ff8000000000000) == 0x7ff8000000000000; 477 return 2 * (ix ^ 0x0008000000000000) > 2 * 0x7ff8000000000000ULL; 478} 479 480#if USE_MPFR 481static mpfr_rnd_t 482rmap (int r) 483{ 484 switch (r) 485 { 486 case FE_TONEAREST: 487 return MPFR_RNDN; 488 case FE_TOWARDZERO: 489 return MPFR_RNDZ; 490 case FE_UPWARD: 491 return MPFR_RNDU; 492 case FE_DOWNWARD: 493 return MPFR_RNDD; 494 } 495 return -1; 496} 497 498#define prec_mpfr_f 50 499#define prec_mpfr_d 80 500#define prec_f 24 501#define prec_d 53 502#define emin_f -148 503#define emin_d -1073 504#define emax_f 128 505#define emax_d 1024 506static inline int 507call_mpfr_f1 (mpfr_t y, const struct fun *f, struct args_f1 a, mpfr_rnd_t r) 508{ 509 MPFR_DECL_INIT (x, prec_f); 510 mpfr_set_flt (x, a.x, MPFR_RNDN); 511 return f->fun_mpfr.f1 (y, x, r); 512} 513static inline int 514call_mpfr_f2 (mpfr_t y, const struct fun *f, struct args_f2 a, mpfr_rnd_t r) 515{ 516 MPFR_DECL_INIT (x, prec_f); 517 MPFR_DECL_INIT (x2, prec_f); 518 mpfr_set_flt (x, a.x, MPFR_RNDN); 519 mpfr_set_flt (x2, a.x2, MPFR_RNDN); 520 return f->fun_mpfr.f2 (y, x, x2, r); 521} 522static inline int 523call_mpfr_d1 (mpfr_t y, const struct fun *f, struct args_d1 a, mpfr_rnd_t r) 524{ 525 MPFR_DECL_INIT (x, prec_d); 526 mpfr_set_d (x, a.x, MPFR_RNDN); 527 return f->fun_mpfr.d1 (y, x, r); 528} 529static inline int 530call_mpfr_d2 (mpfr_t y, const struct fun *f, struct args_d2 a, mpfr_rnd_t r) 531{ 532 MPFR_DECL_INIT (x, prec_d); 533 MPFR_DECL_INIT (x2, prec_d); 534 mpfr_set_d (x, a.x, MPFR_RNDN); 535 mpfr_set_d (x2, a.x2, MPFR_RNDN); 536 return f->fun_mpfr.d2 (y, x, x2, r); 537} 538#endif 539 540#define float_f float 541#define double_f double 542#define copysign_f copysignf 543#define nextafter_f nextafterf 544#define fabs_f fabsf 545#define asuint_f asuint 546#define asfloat_f asfloat 547#define scalbn_f scalbnf 548#define lscalbn_f scalbn 549#define halfinf_f 0x1p127f 550#define min_normal_f 0x1p-126f 551 552#define float_d double 553#define double_d long double 554#define copysign_d copysign 555#define nextafter_d nextafter 556#define fabs_d fabs 557#define asuint_d asuint64 558#define asfloat_d asdouble 559#define scalbn_d scalbn 560#define lscalbn_d scalbnl 561#define halfinf_d 0x1p1023 562#define min_normal_d 0x1p-1022 563 564#define NEW_RT 565#define RT(x) x##_f 566#define T(x) x##_f1 567#include "ulp.h" 568#undef T 569#define T(x) x##_f2 570#include "ulp.h" 571#undef T 572#undef RT 573 574#define NEW_RT 575#define RT(x) x##_d 576#define T(x) x##_d1 577#include "ulp.h" 578#undef T 579#define T(x) x##_d2 580#include "ulp.h" 581#undef T 582#undef RT 583 584static void 585usage (void) 586{ 587 puts ("./ulp [-q] [-m] [-f] [-r {n|u|d|z}] [-l soft-ulplimit] [-e ulplimit] func " 588 "lo [hi [x lo2 hi2] [count]]"); 589 puts ("Compares func against a higher precision implementation in [lo; hi]."); 590 puts ("-q: quiet."); 591 puts ("-m: use mpfr even if faster method is available."); 592 puts ("-f: disable fenv exceptions testing."); 593#ifdef ___vpcs 594 puts ("-c: neutral 'control value' to test behaviour when one lane can affect another. \n" 595 " This should be different from tested input in other lanes, and non-special \n" 596 " (i.e. should not trigger fenv exceptions). Default is 1."); 597#endif 598 puts ("-z: ignore sign of 0."); 599 puts ("Supported func:"); 600 for (const struct fun *f = fun; f->name; f++) 601 printf ("\t%s\n", f->name); 602 exit (1); 603} 604 605static int 606cmp (const struct fun *f, struct gen *gen, const struct conf *conf) 607{ 608 int r = 1; 609 if (f->arity == 1 && f->singleprec) 610 r = cmp_f1 (f, gen, conf); 611 else if (f->arity == 2 && f->singleprec) 612 r = cmp_f2 (f, gen, conf); 613 else if (f->arity == 1 && !f->singleprec) 614 r = cmp_d1 (f, gen, conf); 615 else if (f->arity == 2 && !f->singleprec) 616 r = cmp_d2 (f, gen, conf); 617 else 618 usage (); 619 return r; 620} 621 622static uint64_t 623getnum (const char *s, int singleprec) 624{ 625 // int i; 626 uint64_t sign = 0; 627 // char buf[12]; 628 629 if (s[0] == '+') 630 s++; 631 else if (s[0] == '-') 632 { 633 sign = singleprec ? 1ULL << 31 : 1ULL << 63; 634 s++; 635 } 636 /* 0xXXXX is treated as bit representation, '-' flips the sign bit. */ 637 if (s[0] == '0' && tolower (s[1]) == 'x' && strchr (s, 'p') == 0) 638 return sign ^ strtoull (s, 0, 0); 639 // /* SNaN, QNaN, NaN, Inf. */ 640 // for (i=0; s[i] && i < sizeof buf; i++) 641 // buf[i] = tolower(s[i]); 642 // buf[i] = 0; 643 // if (strcmp(buf, "snan") == 0) 644 // return sign | (singleprec ? 0x7fa00000 : 0x7ff4000000000000); 645 // if (strcmp(buf, "qnan") == 0 || strcmp(buf, "nan") == 0) 646 // return sign | (singleprec ? 0x7fc00000 : 0x7ff8000000000000); 647 // if (strcmp(buf, "inf") == 0 || strcmp(buf, "infinity") == 0) 648 // return sign | (singleprec ? 0x7f800000 : 0x7ff0000000000000); 649 /* Otherwise assume it's a floating-point literal. */ 650 return sign 651 | (singleprec ? asuint (strtof (s, 0)) : asuint64 (strtod (s, 0))); 652} 653 654static void 655parsegen (struct gen *g, int argc, char *argv[], const struct fun *f) 656{ 657 int singleprec = f->singleprec; 658 int arity = f->arity; 659 uint64_t a, b, a2, b2, n; 660 if (argc < 1) 661 usage (); 662 b = a = getnum (argv[0], singleprec); 663 n = 0; 664 if (argc > 1 && strcmp (argv[1], "x") == 0) 665 { 666 argc -= 2; 667 argv += 2; 668 } 669 else if (argc > 1) 670 { 671 b = getnum (argv[1], singleprec); 672 if (argc > 2 && strcmp (argv[2], "x") == 0) 673 { 674 argc -= 3; 675 argv += 3; 676 } 677 } 678 b2 = a2 = getnum (argv[0], singleprec); 679 if (argc > 1) 680 b2 = getnum (argv[1], singleprec); 681 if (argc > 2) 682 n = strtoull (argv[2], 0, 0); 683 if (argc > 3) 684 usage (); 685 //printf("ab %lx %lx ab2 %lx %lx n %lu\n", a, b, a2, b2, n); 686 if (arity == 1) 687 { 688 g->start = a; 689 g->len = b - a; 690 if (n - 1 > b - a) 691 n = b - a + 1; 692 g->off = 0; 693 g->step = n ? (g->len + 1) / n : 1; 694 g->start2 = g->len2 = 0; 695 g->cnt = n; 696 } 697 else if (arity == 2) 698 { 699 g->start = a; 700 g->len = b - a; 701 g->off = g->step = 0; 702 g->start2 = a2; 703 g->len2 = b2 - a2; 704 g->cnt = n; 705 } 706 else 707 usage (); 708} 709 710int 711main (int argc, char *argv[]) 712{ 713 const struct fun *f; 714 struct gen gen; 715 struct conf conf; 716 conf.rc = 'n'; 717 conf.quiet = 0; 718 conf.mpfr = 0; 719 conf.fenv = 1; 720 conf.softlim = 0; 721 conf.errlim = INFINITY; 722 conf.ignore_zero_sign = 0; 723 for (;;) 724 { 725 argc--; 726 argv++; 727 if (argc < 1) 728 usage (); 729 if (argv[0][0] != '-') 730 break; 731 switch (argv[0][1]) 732 { 733 case 'e': 734 argc--; 735 argv++; 736 if (argc < 1) 737 usage (); 738 conf.errlim = strtod (argv[0], 0); 739 break; 740 case 'f': 741 conf.fenv = 0; 742 break; 743 case 'l': 744 argc--; 745 argv++; 746 if (argc < 1) 747 usage (); 748 conf.softlim = strtod (argv[0], 0); 749 break; 750 case 'm': 751 conf.mpfr = 1; 752 break; 753 case 'q': 754 conf.quiet = 1; 755 break; 756 case 'r': 757 conf.rc = argv[0][2]; 758 if (!conf.rc) 759 { 760 argc--; 761 argv++; 762 if (argc < 1 || argv[0][1] != '\0') 763 usage (); 764 conf.rc = argv[0][0]; 765 } 766 break; 767 case 'z': 768 conf.ignore_zero_sign = 1; 769 break; 770#ifdef __vpcs 771 case 'c': 772 argc--; 773 argv++; 774 fv[0] = strtof(argv[0], 0); 775 dv[0] = strtod(argv[0], 0); 776 break; 777#endif 778 default: 779 usage (); 780 } 781 } 782 switch (conf.rc) 783 { 784 case 'n': 785 conf.r = FE_TONEAREST; 786 break; 787 case 'u': 788 conf.r = FE_UPWARD; 789 break; 790 case 'd': 791 conf.r = FE_DOWNWARD; 792 break; 793 case 'z': 794 conf.r = FE_TOWARDZERO; 795 break; 796 default: 797 usage (); 798 } 799 for (f = fun; f->name; f++) 800 if (strcmp (argv[0], f->name) == 0) 801 break; 802 if (!f->name) 803 { 804#ifndef __vpcs 805 /* Ignore vector math functions if vector math is not supported. */ 806 if (strncmp (argv[0], "_ZGVnN", 6) == 0) 807 exit (0); 808#endif 809#if !WANT_SVE_MATH 810 if (strncmp (argv[0], "_ZGVsMxv", 8) == 0) 811 exit (0); 812#endif 813 printf ("math function %s not supported\n", argv[0]); 814 exit (1); 815 } 816 if (!f->singleprec && LDBL_MANT_DIG == DBL_MANT_DIG) 817 conf.mpfr = 1; /* Use mpfr if long double has no extra precision. */ 818 if (!USE_MPFR && conf.mpfr) 819 { 820 puts ("mpfr is not available."); 821 return 0; 822 } 823 argc--; 824 argv++; 825 parsegen (&gen, argc, argv, f); 826 conf.n = gen.cnt; 827 return cmp (f, &gen, &conf); 828} 829