xref: /freebsd-src/contrib/arm-optimized-routines/math/test/ulp.h (revision f3087bef11543b42e0d69b708f367097a4118d24)
131914882SAlex Richardson /*
231914882SAlex Richardson  * Generic functions for ULP error estimation.
331914882SAlex Richardson  *
4*f3087befSAndrew Turner  * Copyright (c) 2019-2024, Arm Limited.
5072a4ba8SAndrew Turner  * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
631914882SAlex Richardson  */
731914882SAlex Richardson 
831914882SAlex Richardson /* For each different math function type,
931914882SAlex Richardson    T(x) should add a different suffix to x.
1031914882SAlex Richardson    RT(x) should add a return type specific suffix to x.  */
1131914882SAlex Richardson 
1231914882SAlex Richardson #ifdef NEW_RT
1331914882SAlex Richardson #undef NEW_RT
1431914882SAlex Richardson 
1531914882SAlex Richardson # if USE_MPFR
1631914882SAlex Richardson static int RT(ulpscale_mpfr) (mpfr_t x, int t)
1731914882SAlex Richardson {
1831914882SAlex Richardson   /* TODO: pow of 2 cases.  */
1931914882SAlex Richardson   if (mpfr_regular_p (x))
2031914882SAlex Richardson     {
2131914882SAlex Richardson       mpfr_exp_t e = mpfr_get_exp (x) - RT(prec);
2231914882SAlex Richardson       if (e < RT(emin))
2331914882SAlex Richardson 	e = RT(emin) - 1;
2431914882SAlex Richardson       if (e > RT(emax) - RT(prec))
2531914882SAlex Richardson 	e = RT(emax) - RT(prec);
2631914882SAlex Richardson       return e;
2731914882SAlex Richardson     }
2831914882SAlex Richardson   if (mpfr_zero_p (x))
2931914882SAlex Richardson     return RT(emin) - 1;
3031914882SAlex Richardson   if (mpfr_inf_p (x))
3131914882SAlex Richardson     return RT(emax) - RT(prec);
3231914882SAlex Richardson   /* NaN.  */
3331914882SAlex Richardson   return 0;
3431914882SAlex Richardson }
3531914882SAlex Richardson # endif
3631914882SAlex Richardson 
3731914882SAlex Richardson /* Difference between exact result and closest real number that
3831914882SAlex Richardson    gets rounded to got, i.e. error before rounding, for a correctly
3931914882SAlex Richardson    rounded result the difference is 0.  */
405a02ffc3SAndrew Turner static double RT (ulperr) (RT (float) got, const struct RT (ret) * p, int r,
415a02ffc3SAndrew Turner 			   int ignore_zero_sign)
4231914882SAlex Richardson {
4331914882SAlex Richardson   RT(float) want = p->y;
4431914882SAlex Richardson   RT(float) d;
4531914882SAlex Richardson   double e;
4631914882SAlex Richardson 
4731914882SAlex Richardson   if (RT(asuint) (got) == RT(asuint) (want))
4831914882SAlex Richardson     return 0.0;
495a02ffc3SAndrew Turner   if (isnan (got) && isnan (want))
50*f3087befSAndrew Turner   /* Ignore sign of NaN, and signalling-ness for MPFR.  */
51*f3087befSAndrew Turner # if USE_MPFR
52*f3087befSAndrew Turner     return 0;
53*f3087befSAndrew Turner # else
545a02ffc3SAndrew Turner     return RT (issignaling) (got) == RT (issignaling) (want) ? 0 : INFINITY;
55*f3087befSAndrew Turner # endif
5631914882SAlex Richardson   if (signbit (got) != signbit (want))
575a02ffc3SAndrew Turner     {
585a02ffc3SAndrew Turner       /* Fall through to ULP calculation if ignoring sign of zero and at
595a02ffc3SAndrew Turner 	 exactly one of want and got is non-zero.  */
605a02ffc3SAndrew Turner       if (ignore_zero_sign && want == got)
615a02ffc3SAndrew Turner 	return 0.0;
625a02ffc3SAndrew Turner       if (!ignore_zero_sign || (want != 0 && got != 0))
6331914882SAlex Richardson 	return INFINITY;
645a02ffc3SAndrew Turner     }
6531914882SAlex Richardson   if (!isfinite (want) || !isfinite (got))
6631914882SAlex Richardson     {
6731914882SAlex Richardson       if (isnan (got) != isnan (want))
6831914882SAlex Richardson 	return INFINITY;
6931914882SAlex Richardson       if (isnan (want))
7031914882SAlex Richardson 	return 0;
7131914882SAlex Richardson       if (isinf (got))
7231914882SAlex Richardson 	{
7331914882SAlex Richardson 	  got = RT(copysign) (RT(halfinf), got);
7431914882SAlex Richardson 	  want *= 0.5f;
7531914882SAlex Richardson 	}
7631914882SAlex Richardson       if (isinf (want))
7731914882SAlex Richardson 	{
7831914882SAlex Richardson 	  want = RT(copysign) (RT(halfinf), want);
7931914882SAlex Richardson 	  got *= 0.5f;
8031914882SAlex Richardson 	}
8131914882SAlex Richardson     }
8231914882SAlex Richardson   if (r == FE_TONEAREST)
8331914882SAlex Richardson     {
8431914882SAlex Richardson       // TODO: incorrect when got vs want cross a powof2 boundary
8531914882SAlex Richardson       /* error = got > want
8631914882SAlex Richardson 	      ? got - want - tail ulp - 0.5 ulp
87*f3087befSAndrew Turner 	      : got - want - tail ulp + 0.5 ulp.  */
8831914882SAlex Richardson       d = got - want;
8931914882SAlex Richardson       e = d > 0 ? -p->tail - 0.5 : -p->tail + 0.5;
9031914882SAlex Richardson     }
9131914882SAlex Richardson   else
9231914882SAlex Richardson     {
9331914882SAlex Richardson       if ((r == FE_DOWNWARD && got < want) || (r == FE_UPWARD && got > want)
9431914882SAlex Richardson 	  || (r == FE_TOWARDZERO && fabs (got) < fabs (want)))
9531914882SAlex Richardson 	got = RT(nextafter) (got, want);
9631914882SAlex Richardson       d = got - want;
9731914882SAlex Richardson       e = -p->tail;
9831914882SAlex Richardson     }
9931914882SAlex Richardson   return RT(scalbn) (d, -p->ulpexp) + e;
10031914882SAlex Richardson }
10131914882SAlex Richardson 
10231914882SAlex Richardson static int RT(isok) (RT(float) ygot, int exgot, RT(float) ywant, int exwant,
10331914882SAlex Richardson 		      int exmay)
10431914882SAlex Richardson {
10531914882SAlex Richardson   return RT(asuint) (ygot) == RT(asuint) (ywant)
10631914882SAlex Richardson 	 && ((exgot ^ exwant) & ~exmay) == 0;
10731914882SAlex Richardson }
10831914882SAlex Richardson 
10931914882SAlex Richardson static int RT(isok_nofenv) (RT(float) ygot, RT(float) ywant)
11031914882SAlex Richardson {
11131914882SAlex Richardson   return RT(asuint) (ygot) == RT(asuint) (ywant);
11231914882SAlex Richardson }
11331914882SAlex Richardson #endif
11431914882SAlex Richardson 
115*f3087befSAndrew Turner static inline void T (call_fenv) (const struct fun *f, struct T (args) a,
116*f3087befSAndrew Turner 				  int r, RT (float) * y, int *ex,
117*f3087befSAndrew Turner 				  const struct conf *conf)
11831914882SAlex Richardson {
11931914882SAlex Richardson   if (r != FE_TONEAREST)
12031914882SAlex Richardson     fesetround (r);
12131914882SAlex Richardson   feclearexcept (FE_ALL_EXCEPT);
122*f3087befSAndrew Turner   *y = T (call) (f, a, conf);
12331914882SAlex Richardson   *ex = fetestexcept (FE_ALL_EXCEPT);
12431914882SAlex Richardson   if (r != FE_TONEAREST)
12531914882SAlex Richardson     fesetround (FE_TONEAREST);
12631914882SAlex Richardson }
12731914882SAlex Richardson 
12831914882SAlex Richardson static inline void T (call_nofenv) (const struct fun *f, struct T (args) a,
129*f3087befSAndrew Turner 				    int r, RT (float) * y, int *ex,
130*f3087befSAndrew Turner 				    const struct conf *conf)
13131914882SAlex Richardson {
1325a02ffc3SAndrew Turner   if (r != FE_TONEAREST)
1335a02ffc3SAndrew Turner     fesetround (r);
134*f3087befSAndrew Turner   *y = T (call) (f, a, conf);
13531914882SAlex Richardson   *ex = 0;
1365a02ffc3SAndrew Turner   if (r != FE_TONEAREST)
1375a02ffc3SAndrew Turner     fesetround (FE_TONEAREST);
13831914882SAlex Richardson }
13931914882SAlex Richardson 
14031914882SAlex Richardson static inline int T (call_long_fenv) (const struct fun *f, struct T (args) a,
14131914882SAlex Richardson 				      int r, struct RT (ret) * p,
14231914882SAlex Richardson 				      RT (float) ygot, int exgot)
14331914882SAlex Richardson {
14431914882SAlex Richardson   if (r != FE_TONEAREST)
14531914882SAlex Richardson     fesetround (r);
14631914882SAlex Richardson   feclearexcept (FE_ALL_EXCEPT);
14731914882SAlex Richardson   volatile struct T(args) va = a; // TODO: barrier
14831914882SAlex Richardson   a = va;
14931914882SAlex Richardson   RT(double) yl = T(call_long) (f, a);
15031914882SAlex Richardson   p->y = (RT(float)) yl;
15131914882SAlex Richardson   volatile RT(float) vy = p->y; // TODO: barrier
15231914882SAlex Richardson   (void) vy;
15331914882SAlex Richardson   p->ex = fetestexcept (FE_ALL_EXCEPT);
15431914882SAlex Richardson   if (r != FE_TONEAREST)
15531914882SAlex Richardson     fesetround (FE_TONEAREST);
15631914882SAlex Richardson   p->ex_may = FE_INEXACT;
15731914882SAlex Richardson   if (RT(isok) (ygot, exgot, p->y, p->ex, p->ex_may))
15831914882SAlex Richardson     return 1;
15931914882SAlex Richardson   p->ulpexp = RT(ulpscale) (p->y);
16031914882SAlex Richardson   if (isinf (p->y))
16131914882SAlex Richardson     p->tail = RT(lscalbn) (yl - (RT(double)) 2 * RT(halfinf), -p->ulpexp);
16231914882SAlex Richardson   else
16331914882SAlex Richardson     p->tail = RT(lscalbn) (yl - p->y, -p->ulpexp);
16431914882SAlex Richardson   if (RT(fabs) (p->y) < RT(min_normal))
16531914882SAlex Richardson     {
16631914882SAlex Richardson       /* TODO: subnormal result is treated as undeflow even if it's
16731914882SAlex Richardson 	 exact since call_long may not raise inexact correctly.  */
16831914882SAlex Richardson       if (p->y != 0 || (p->ex & FE_INEXACT))
16931914882SAlex Richardson 	p->ex |= FE_UNDERFLOW | FE_INEXACT;
17031914882SAlex Richardson     }
17131914882SAlex Richardson   return 0;
17231914882SAlex Richardson }
17331914882SAlex Richardson static inline int T(call_long_nofenv) (const struct fun *f, struct T(args) a,
17431914882SAlex Richardson 					int r, struct RT(ret) * p,
17531914882SAlex Richardson 					RT(float) ygot, int exgot)
17631914882SAlex Richardson {
1775a02ffc3SAndrew Turner   if (r != FE_TONEAREST)
1785a02ffc3SAndrew Turner     fesetround (r);
17931914882SAlex Richardson   RT(double) yl = T(call_long) (f, a);
18031914882SAlex Richardson   p->y = (RT(float)) yl;
1815a02ffc3SAndrew Turner   if (r != FE_TONEAREST)
1825a02ffc3SAndrew Turner     fesetround (FE_TONEAREST);
18331914882SAlex Richardson   if (RT(isok_nofenv) (ygot, p->y))
18431914882SAlex Richardson     return 1;
18531914882SAlex Richardson   p->ulpexp = RT(ulpscale) (p->y);
18631914882SAlex Richardson   if (isinf (p->y))
18731914882SAlex Richardson     p->tail = RT(lscalbn) (yl - (RT(double)) 2 * RT(halfinf), -p->ulpexp);
18831914882SAlex Richardson   else
18931914882SAlex Richardson     p->tail = RT(lscalbn) (yl - p->y, -p->ulpexp);
19031914882SAlex Richardson   return 0;
19131914882SAlex Richardson }
19231914882SAlex Richardson 
19331914882SAlex Richardson /* There are nan input args and all quiet.  */
19431914882SAlex Richardson static inline int T(qnanpropagation) (struct T(args) a)
19531914882SAlex Richardson {
19631914882SAlex Richardson   return T(reduce) (a, isnan, ||) && !T(reduce) (a, RT(issignaling), ||);
19731914882SAlex Richardson }
19831914882SAlex Richardson static inline RT(float) T(sum) (struct T(args) a)
19931914882SAlex Richardson {
20031914882SAlex Richardson   return T(reduce) (a, , +);
20131914882SAlex Richardson }
20231914882SAlex Richardson 
20331914882SAlex Richardson /* returns 1 if the got result is ok.  */
20431914882SAlex Richardson static inline int T(call_mpfr_fix) (const struct fun *f, struct T(args) a,
20531914882SAlex Richardson 				     int r_fenv, struct RT(ret) * p,
20631914882SAlex Richardson 				     RT(float) ygot, int exgot)
20731914882SAlex Richardson {
20831914882SAlex Richardson #if USE_MPFR
20931914882SAlex Richardson   int t, t2;
21031914882SAlex Richardson   mpfr_rnd_t r = rmap (r_fenv);
21131914882SAlex Richardson   MPFR_DECL_INIT(my, RT(prec_mpfr));
21231914882SAlex Richardson   MPFR_DECL_INIT(mr, RT(prec));
21331914882SAlex Richardson   MPFR_DECL_INIT(me, RT(prec_mpfr));
21431914882SAlex Richardson   mpfr_clear_flags ();
21531914882SAlex Richardson   t = T(call_mpfr) (my, f, a, r);
21631914882SAlex Richardson   /* Double rounding.  */
21731914882SAlex Richardson   t2 = mpfr_set (mr, my, r);
21831914882SAlex Richardson   if (t2)
21931914882SAlex Richardson     t = t2;
22031914882SAlex Richardson   mpfr_set_emin (RT(emin));
22131914882SAlex Richardson   mpfr_set_emax (RT(emax));
22231914882SAlex Richardson   t = mpfr_check_range (mr, t, r);
22331914882SAlex Richardson   t = mpfr_subnormalize (mr, t, r);
22431914882SAlex Richardson   mpfr_set_emax (MPFR_EMAX_DEFAULT);
22531914882SAlex Richardson   mpfr_set_emin (MPFR_EMIN_DEFAULT);
22631914882SAlex Richardson   p->y = mpfr_get_d (mr, r);
22731914882SAlex Richardson   p->ex = t ? FE_INEXACT : 0;
22831914882SAlex Richardson   p->ex_may = FE_INEXACT;
22931914882SAlex Richardson   if (mpfr_underflow_p () && (p->ex & FE_INEXACT))
23031914882SAlex Richardson     /* TODO: handle before and after rounding uflow cases.  */
23131914882SAlex Richardson     p->ex |= FE_UNDERFLOW;
23231914882SAlex Richardson   if (mpfr_overflow_p ())
23331914882SAlex Richardson     p->ex |= FE_OVERFLOW | FE_INEXACT;
23431914882SAlex Richardson   if (mpfr_divby0_p ())
23531914882SAlex Richardson     p->ex |= FE_DIVBYZERO;
23631914882SAlex Richardson   //if (mpfr_erangeflag_p ())
23731914882SAlex Richardson   //  p->ex |= FE_INVALID;
23831914882SAlex Richardson   if (!mpfr_nanflag_p () && RT(isok) (ygot, exgot, p->y, p->ex, p->ex_may))
23931914882SAlex Richardson     return 1;
24031914882SAlex Richardson   if (mpfr_nanflag_p () && !T(qnanpropagation) (a))
24131914882SAlex Richardson     p->ex |= FE_INVALID;
24231914882SAlex Richardson   p->ulpexp = RT(ulpscale_mpfr) (my, t);
24331914882SAlex Richardson   if (!isfinite (p->y))
24431914882SAlex Richardson     {
24531914882SAlex Richardson       p->tail = 0;
24631914882SAlex Richardson       if (isnan (p->y))
24731914882SAlex Richardson 	{
24831914882SAlex Richardson 	  /* If an input was nan keep its sign.  */
24931914882SAlex Richardson 	  p->y = T(sum) (a);
25031914882SAlex Richardson 	  if (!isnan (p->y))
25131914882SAlex Richardson 	    p->y = (p->y - p->y) / (p->y - p->y);
25231914882SAlex Richardson 	  return RT(isok) (ygot, exgot, p->y, p->ex, p->ex_may);
25331914882SAlex Richardson 	}
25431914882SAlex Richardson       mpfr_set_si_2exp (mr, signbit (p->y) ? -1 : 1, 1024, MPFR_RNDN);
25531914882SAlex Richardson       if (mpfr_cmpabs (my, mr) >= 0)
25631914882SAlex Richardson 	return RT(isok) (ygot, exgot, p->y, p->ex, p->ex_may);
25731914882SAlex Richardson     }
25831914882SAlex Richardson   mpfr_sub (me, my, mr, MPFR_RNDN);
25931914882SAlex Richardson   mpfr_mul_2si (me, me, -p->ulpexp, MPFR_RNDN);
26031914882SAlex Richardson   p->tail = mpfr_get_d (me, MPFR_RNDN);
26131914882SAlex Richardson   return 0;
26231914882SAlex Richardson #else
26331914882SAlex Richardson   abort ();
26431914882SAlex Richardson #endif
26531914882SAlex Richardson }
26631914882SAlex Richardson 
26731914882SAlex Richardson static int T(cmp) (const struct fun *f, struct gen *gen,
26831914882SAlex Richardson 		     const struct conf *conf)
26931914882SAlex Richardson {
27031914882SAlex Richardson   double maxerr = 0;
27131914882SAlex Richardson   uint64_t cnt = 0;
27231914882SAlex Richardson   uint64_t cnt1 = 0;
27331914882SAlex Richardson   uint64_t cnt2 = 0;
27431914882SAlex Richardson   uint64_t cntfail = 0;
27531914882SAlex Richardson   int r = conf->r;
27631914882SAlex Richardson   int use_mpfr = conf->mpfr;
27731914882SAlex Richardson   int fenv = conf->fenv;
278*f3087befSAndrew Turner 
27931914882SAlex Richardson   for (;;)
28031914882SAlex Richardson     {
28131914882SAlex Richardson       struct RT(ret) want;
28231914882SAlex Richardson       struct T(args) a = T(next) (gen);
28331914882SAlex Richardson       int exgot;
28431914882SAlex Richardson       int exgot2;
28531914882SAlex Richardson       RT(float) ygot;
28631914882SAlex Richardson       RT(float) ygot2;
28731914882SAlex Richardson       int fail = 0;
28831914882SAlex Richardson       if (fenv)
289*f3087befSAndrew Turner 	T (call_fenv) (f, a, r, &ygot, &exgot, conf);
29031914882SAlex Richardson       else
291*f3087befSAndrew Turner 	T (call_nofenv) (f, a, r, &ygot, &exgot, conf);
29231914882SAlex Richardson       if (f->twice) {
29331914882SAlex Richardson 	secondcall = 1;
29431914882SAlex Richardson 	if (fenv)
295*f3087befSAndrew Turner 	  T (call_fenv) (f, a, r, &ygot2, &exgot2, conf);
29631914882SAlex Richardson 	else
297*f3087befSAndrew Turner 	  T (call_nofenv) (f, a, r, &ygot2, &exgot2, conf);
29831914882SAlex Richardson 	secondcall = 0;
29931914882SAlex Richardson 	if (RT(asuint) (ygot) != RT(asuint) (ygot2))
30031914882SAlex Richardson 	  {
30131914882SAlex Richardson 	    fail = 1;
30231914882SAlex Richardson 	    cntfail++;
30331914882SAlex Richardson 	    T(printcall) (f, a);
30431914882SAlex Richardson 	    printf (" got %a then %a for same input\n", ygot, ygot2);
30531914882SAlex Richardson 	  }
30631914882SAlex Richardson       }
30731914882SAlex Richardson       cnt++;
30831914882SAlex Richardson       int ok = use_mpfr
30931914882SAlex Richardson 		 ? T(call_mpfr_fix) (f, a, r, &want, ygot, exgot)
31031914882SAlex Richardson 		 : (fenv ? T(call_long_fenv) (f, a, r, &want, ygot, exgot)
31131914882SAlex Richardson 			 : T(call_long_nofenv) (f, a, r, &want, ygot, exgot));
31231914882SAlex Richardson       if (!ok)
31331914882SAlex Richardson 	{
31431914882SAlex Richardson 	  int print = 0;
3155a02ffc3SAndrew Turner 	  double err = RT (ulperr) (ygot, &want, r, conf->ignore_zero_sign);
31631914882SAlex Richardson 	  double abserr = fabs (err);
31731914882SAlex Richardson 	  // TODO: count errors below accuracy limit.
31831914882SAlex Richardson 	  if (abserr > 0)
31931914882SAlex Richardson 	    cnt1++;
32031914882SAlex Richardson 	  if (abserr > 1)
32131914882SAlex Richardson 	    cnt2++;
32231914882SAlex Richardson 	  if (abserr > conf->errlim)
32331914882SAlex Richardson 	    {
32431914882SAlex Richardson 	      print = 1;
32531914882SAlex Richardson 	      if (!fail)
32631914882SAlex Richardson 		{
32731914882SAlex Richardson 		  fail = 1;
32831914882SAlex Richardson 		  cntfail++;
32931914882SAlex Richardson 		}
33031914882SAlex Richardson 	    }
33131914882SAlex Richardson 	  if (abserr > maxerr)
33231914882SAlex Richardson 	    {
33331914882SAlex Richardson 	      maxerr = abserr;
33431914882SAlex Richardson 	      if (!conf->quiet && abserr > conf->softlim)
33531914882SAlex Richardson 		print = 1;
33631914882SAlex Richardson 	    }
33731914882SAlex Richardson 	  if (print)
33831914882SAlex Richardson 	    {
33931914882SAlex Richardson 	      T(printcall) (f, a);
34031914882SAlex Richardson 	      // TODO: inf ulp handling
34131914882SAlex Richardson 	      printf (" got %a want %a %+g ulp err %g\n", ygot, want.y,
34231914882SAlex Richardson 		      want.tail, err);
34331914882SAlex Richardson 	    }
34431914882SAlex Richardson 	  int diff = fenv ? exgot ^ want.ex : 0;
34531914882SAlex Richardson 	  if (fenv && (diff & ~want.ex_may))
34631914882SAlex Richardson 	    {
34731914882SAlex Richardson 	      if (!fail)
34831914882SAlex Richardson 		{
34931914882SAlex Richardson 		  fail = 1;
35031914882SAlex Richardson 		  cntfail++;
35131914882SAlex Richardson 		}
35231914882SAlex Richardson 	      T(printcall) (f, a);
35331914882SAlex Richardson 	      printf (" is %a %+g ulp, got except 0x%0x", want.y, want.tail,
35431914882SAlex Richardson 		      exgot);
35531914882SAlex Richardson 	      if (diff & exgot)
35631914882SAlex Richardson 		printf (" wrongly set: 0x%x", diff & exgot);
35731914882SAlex Richardson 	      if (diff & ~exgot)
35831914882SAlex Richardson 		printf (" wrongly clear: 0x%x", diff & ~exgot);
35931914882SAlex Richardson 	      putchar ('\n');
36031914882SAlex Richardson 	    }
36131914882SAlex Richardson 	}
36231914882SAlex Richardson       if (cnt >= conf->n)
36331914882SAlex Richardson 	break;
36431914882SAlex Richardson       if (!conf->quiet && cnt % 0x100000 == 0)
36531914882SAlex Richardson 	printf ("progress: %6.3f%% cnt %llu cnt1 %llu cnt2 %llu cntfail %llu "
36631914882SAlex Richardson 		"maxerr %g\n",
36731914882SAlex Richardson 		100.0 * cnt / conf->n, (unsigned long long) cnt,
36831914882SAlex Richardson 		(unsigned long long) cnt1, (unsigned long long) cnt2,
36931914882SAlex Richardson 		(unsigned long long) cntfail, maxerr);
37031914882SAlex Richardson     }
37131914882SAlex Richardson   double cc = cnt;
37231914882SAlex Richardson   if (cntfail)
37331914882SAlex Richardson     printf ("FAIL ");
37431914882SAlex Richardson   else
37531914882SAlex Richardson     printf ("PASS ");
37631914882SAlex Richardson   T(printgen) (f, gen);
37731914882SAlex Richardson   printf (" round %c errlim %g maxerr %g %s cnt %llu cnt1 %llu %g%% cnt2 %llu "
37831914882SAlex Richardson 	  "%g%% cntfail %llu %g%%\n",
37931914882SAlex Richardson 	  conf->rc, conf->errlim,
38031914882SAlex Richardson 	  maxerr, conf->r == FE_TONEAREST ? "+0.5" : "+1.0",
38131914882SAlex Richardson 	  (unsigned long long) cnt,
38231914882SAlex Richardson 	  (unsigned long long) cnt1, 100.0 * cnt1 / cc,
38331914882SAlex Richardson 	  (unsigned long long) cnt2, 100.0 * cnt2 / cc,
38431914882SAlex Richardson 	  (unsigned long long) cntfail, 100.0 * cntfail / cc);
38531914882SAlex Richardson   return !!cntfail;
38631914882SAlex Richardson }
387