xref: /llvm-project/libc/AOR_v20.02/math/test/ulp.h (revision 0928368f623a0f885894f9c3ef1b740b060c0d9c)
1*0928368fSKristof Beyls /*
2*0928368fSKristof Beyls  * Generic functions for ULP error estimation.
3*0928368fSKristof Beyls  *
4*0928368fSKristof Beyls  * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5*0928368fSKristof Beyls  * See https://llvm.org/LICENSE.txt for license information.
6*0928368fSKristof Beyls  * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7*0928368fSKristof Beyls  */
8*0928368fSKristof Beyls 
9*0928368fSKristof Beyls /* For each different math function type,
10*0928368fSKristof Beyls    T(x) should add a different suffix to x.
11*0928368fSKristof Beyls    RT(x) should add a return type specific suffix to x. */
12*0928368fSKristof Beyls 
13*0928368fSKristof Beyls #ifdef NEW_RT
14*0928368fSKristof Beyls #undef NEW_RT
15*0928368fSKristof Beyls 
16*0928368fSKristof Beyls # if USE_MPFR
RT(ulpscale_mpfr)17*0928368fSKristof Beyls static int RT(ulpscale_mpfr) (mpfr_t x, int t)
18*0928368fSKristof Beyls {
19*0928368fSKristof Beyls   /* TODO: pow of 2 cases.  */
20*0928368fSKristof Beyls   if (mpfr_regular_p (x))
21*0928368fSKristof Beyls     {
22*0928368fSKristof Beyls       mpfr_exp_t e = mpfr_get_exp (x) - RT(prec);
23*0928368fSKristof Beyls       if (e < RT(emin))
24*0928368fSKristof Beyls 	e = RT(emin) - 1;
25*0928368fSKristof Beyls       if (e > RT(emax) - RT(prec))
26*0928368fSKristof Beyls 	e = RT(emax) - RT(prec);
27*0928368fSKristof Beyls       return e;
28*0928368fSKristof Beyls     }
29*0928368fSKristof Beyls   if (mpfr_zero_p (x))
30*0928368fSKristof Beyls     return RT(emin) - 1;
31*0928368fSKristof Beyls   if (mpfr_inf_p (x))
32*0928368fSKristof Beyls     return RT(emax) - RT(prec);
33*0928368fSKristof Beyls   /* NaN.  */
34*0928368fSKristof Beyls   return 0;
35*0928368fSKristof Beyls }
36*0928368fSKristof Beyls # endif
37*0928368fSKristof Beyls 
38*0928368fSKristof Beyls /* Difference between exact result and closest real number that
39*0928368fSKristof Beyls    gets rounded to got, i.e. error before rounding, for a correctly
40*0928368fSKristof Beyls    rounded result the difference is 0.  */
RT(ulperr)41*0928368fSKristof Beyls static double RT(ulperr) (RT(float) got, const struct RT(ret) * p, int r)
42*0928368fSKristof Beyls {
43*0928368fSKristof Beyls   RT(float) want = p->y;
44*0928368fSKristof Beyls   RT(float) d;
45*0928368fSKristof Beyls   double e;
46*0928368fSKristof Beyls 
47*0928368fSKristof Beyls   if (RT(asuint) (got) == RT(asuint) (want))
48*0928368fSKristof Beyls     return 0.0;
49*0928368fSKristof Beyls   if (signbit (got) != signbit (want))
50*0928368fSKristof Beyls     /* May have false positives with NaN.  */
51*0928368fSKristof Beyls     //return isnan(got) && isnan(want) ? 0 : INFINITY;
52*0928368fSKristof Beyls     return INFINITY;
53*0928368fSKristof Beyls   if (!isfinite (want) || !isfinite (got))
54*0928368fSKristof Beyls     {
55*0928368fSKristof Beyls       if (isnan (got) != isnan (want))
56*0928368fSKristof Beyls 	return INFINITY;
57*0928368fSKristof Beyls       if (isnan (want))
58*0928368fSKristof Beyls 	return 0;
59*0928368fSKristof Beyls       if (isinf (got))
60*0928368fSKristof Beyls 	{
61*0928368fSKristof Beyls 	  got = RT(copysign) (RT(halfinf), got);
62*0928368fSKristof Beyls 	  want *= 0.5f;
63*0928368fSKristof Beyls 	}
64*0928368fSKristof Beyls       if (isinf (want))
65*0928368fSKristof Beyls 	{
66*0928368fSKristof Beyls 	  want = RT(copysign) (RT(halfinf), want);
67*0928368fSKristof Beyls 	  got *= 0.5f;
68*0928368fSKristof Beyls 	}
69*0928368fSKristof Beyls     }
70*0928368fSKristof Beyls   if (r == FE_TONEAREST)
71*0928368fSKristof Beyls     {
72*0928368fSKristof Beyls       // TODO: incorrect when got vs want cross a powof2 boundary
73*0928368fSKristof Beyls       /* error = got > want
74*0928368fSKristof Beyls 	      ? got - want - tail ulp - 0.5 ulp
75*0928368fSKristof Beyls 	      : got - want - tail ulp + 0.5 ulp;  */
76*0928368fSKristof Beyls       d = got - want;
77*0928368fSKristof Beyls       e = d > 0 ? -p->tail - 0.5 : -p->tail + 0.5;
78*0928368fSKristof Beyls     }
79*0928368fSKristof Beyls   else
80*0928368fSKristof Beyls     {
81*0928368fSKristof Beyls       if ((r == FE_DOWNWARD && got < want) || (r == FE_UPWARD && got > want)
82*0928368fSKristof Beyls 	  || (r == FE_TOWARDZERO && fabs (got) < fabs (want)))
83*0928368fSKristof Beyls 	got = RT(nextafter) (got, want);
84*0928368fSKristof Beyls       d = got - want;
85*0928368fSKristof Beyls       e = -p->tail;
86*0928368fSKristof Beyls     }
87*0928368fSKristof Beyls   return RT(scalbn) (d, -p->ulpexp) + e;
88*0928368fSKristof Beyls }
89*0928368fSKristof Beyls 
RT(isok)90*0928368fSKristof Beyls static int RT(isok) (RT(float) ygot, int exgot, RT(float) ywant, int exwant,
91*0928368fSKristof Beyls 		      int exmay)
92*0928368fSKristof Beyls {
93*0928368fSKristof Beyls   return RT(asuint) (ygot) == RT(asuint) (ywant)
94*0928368fSKristof Beyls 	 && ((exgot ^ exwant) & ~exmay) == 0;
95*0928368fSKristof Beyls }
96*0928368fSKristof Beyls 
RT(isok_nofenv)97*0928368fSKristof Beyls static int RT(isok_nofenv) (RT(float) ygot, RT(float) ywant)
98*0928368fSKristof Beyls {
99*0928368fSKristof Beyls   return RT(asuint) (ygot) == RT(asuint) (ywant);
100*0928368fSKristof Beyls }
101*0928368fSKristof Beyls #endif
102*0928368fSKristof Beyls 
T(call_fenv)103*0928368fSKristof Beyls static inline void T(call_fenv) (const struct fun *f, struct T(args) a, int r,
104*0928368fSKristof Beyls 				  RT(float) * y, int *ex)
105*0928368fSKristof Beyls {
106*0928368fSKristof Beyls   if (r != FE_TONEAREST)
107*0928368fSKristof Beyls     fesetround (r);
108*0928368fSKristof Beyls   feclearexcept (FE_ALL_EXCEPT);
109*0928368fSKristof Beyls   *y = T(call) (f, a);
110*0928368fSKristof Beyls   *ex = fetestexcept (FE_ALL_EXCEPT);
111*0928368fSKristof Beyls   if (r != FE_TONEAREST)
112*0928368fSKristof Beyls     fesetround (FE_TONEAREST);
113*0928368fSKristof Beyls }
114*0928368fSKristof Beyls 
T(call_nofenv)115*0928368fSKristof Beyls static inline void T(call_nofenv) (const struct fun *f, struct T(args) a,
116*0928368fSKristof Beyls 				    int r, RT(float) * y, int *ex)
117*0928368fSKristof Beyls {
118*0928368fSKristof Beyls   *y = T(call) (f, a);
119*0928368fSKristof Beyls   *ex = 0;
120*0928368fSKristof Beyls }
121*0928368fSKristof Beyls 
T(call_long_fenv)122*0928368fSKristof Beyls static inline int T(call_long_fenv) (const struct fun *f, struct T(args) a,
123*0928368fSKristof Beyls 				      int r, struct RT(ret) * p,
124*0928368fSKristof Beyls 				      RT(float) ygot, int exgot)
125*0928368fSKristof Beyls {
126*0928368fSKristof Beyls   if (r != FE_TONEAREST)
127*0928368fSKristof Beyls     fesetround (r);
128*0928368fSKristof Beyls   feclearexcept (FE_ALL_EXCEPT);
129*0928368fSKristof Beyls   volatile struct T(args) va = a; // TODO: barrier
130*0928368fSKristof Beyls   a = va;
131*0928368fSKristof Beyls   RT(double) yl = T(call_long) (f, a);
132*0928368fSKristof Beyls   p->y = (RT(float)) yl;
133*0928368fSKristof Beyls   volatile RT(float) vy = p->y; // TODO: barrier
134*0928368fSKristof Beyls   (void) vy;
135*0928368fSKristof Beyls   p->ex = fetestexcept (FE_ALL_EXCEPT);
136*0928368fSKristof Beyls   if (r != FE_TONEAREST)
137*0928368fSKristof Beyls     fesetround (FE_TONEAREST);
138*0928368fSKristof Beyls   p->ex_may = FE_INEXACT;
139*0928368fSKristof Beyls   if (RT(isok) (ygot, exgot, p->y, p->ex, p->ex_may))
140*0928368fSKristof Beyls     return 1;
141*0928368fSKristof Beyls   p->ulpexp = RT(ulpscale) (p->y);
142*0928368fSKristof Beyls   if (isinf (p->y))
143*0928368fSKristof Beyls     p->tail = RT(lscalbn) (yl - (RT(double)) 2 * RT(halfinf), -p->ulpexp);
144*0928368fSKristof Beyls   else
145*0928368fSKristof Beyls     p->tail = RT(lscalbn) (yl - p->y, -p->ulpexp);
146*0928368fSKristof Beyls   if (RT(fabs) (p->y) < RT(min_normal))
147*0928368fSKristof Beyls     {
148*0928368fSKristof Beyls       /* TODO: subnormal result is treated as undeflow even if it's
149*0928368fSKristof Beyls 	 exact since call_long may not raise inexact correctly.  */
150*0928368fSKristof Beyls       if (p->y != 0 || (p->ex & FE_INEXACT))
151*0928368fSKristof Beyls 	p->ex |= FE_UNDERFLOW | FE_INEXACT;
152*0928368fSKristof Beyls     }
153*0928368fSKristof Beyls   return 0;
154*0928368fSKristof Beyls }
T(call_long_nofenv)155*0928368fSKristof Beyls static inline int T(call_long_nofenv) (const struct fun *f, struct T(args) a,
156*0928368fSKristof Beyls 					int r, struct RT(ret) * p,
157*0928368fSKristof Beyls 					RT(float) ygot, int exgot)
158*0928368fSKristof Beyls {
159*0928368fSKristof Beyls   RT(double) yl = T(call_long) (f, a);
160*0928368fSKristof Beyls   p->y = (RT(float)) yl;
161*0928368fSKristof Beyls   if (RT(isok_nofenv) (ygot, p->y))
162*0928368fSKristof Beyls     return 1;
163*0928368fSKristof Beyls   p->ulpexp = RT(ulpscale) (p->y);
164*0928368fSKristof Beyls   if (isinf (p->y))
165*0928368fSKristof Beyls     p->tail = RT(lscalbn) (yl - (RT(double)) 2 * RT(halfinf), -p->ulpexp);
166*0928368fSKristof Beyls   else
167*0928368fSKristof Beyls     p->tail = RT(lscalbn) (yl - p->y, -p->ulpexp);
168*0928368fSKristof Beyls   return 0;
169*0928368fSKristof Beyls }
170*0928368fSKristof Beyls 
171*0928368fSKristof Beyls /* There are nan input args and all quiet.  */
T(qnanpropagation)172*0928368fSKristof Beyls static inline int T(qnanpropagation) (struct T(args) a)
173*0928368fSKristof Beyls {
174*0928368fSKristof Beyls   return T(reduce) (a, isnan, ||) && !T(reduce) (a, RT(issignaling), ||);
175*0928368fSKristof Beyls }
T(sum)176*0928368fSKristof Beyls static inline RT(float) T(sum) (struct T(args) a)
177*0928368fSKristof Beyls {
178*0928368fSKristof Beyls   return T(reduce) (a, , +);
179*0928368fSKristof Beyls }
180*0928368fSKristof Beyls 
181*0928368fSKristof Beyls /* returns 1 if the got result is ok.  */
T(call_mpfr_fix)182*0928368fSKristof Beyls static inline int T(call_mpfr_fix) (const struct fun *f, struct T(args) a,
183*0928368fSKristof Beyls 				     int r_fenv, struct RT(ret) * p,
184*0928368fSKristof Beyls 				     RT(float) ygot, int exgot)
185*0928368fSKristof Beyls {
186*0928368fSKristof Beyls #if USE_MPFR
187*0928368fSKristof Beyls   int t, t2;
188*0928368fSKristof Beyls   mpfr_rnd_t r = rmap (r_fenv);
189*0928368fSKristof Beyls   MPFR_DECL_INIT(my, RT(prec_mpfr));
190*0928368fSKristof Beyls   MPFR_DECL_INIT(mr, RT(prec));
191*0928368fSKristof Beyls   MPFR_DECL_INIT(me, RT(prec_mpfr));
192*0928368fSKristof Beyls   mpfr_clear_flags ();
193*0928368fSKristof Beyls   t = T(call_mpfr) (my, f, a, r);
194*0928368fSKristof Beyls   /* Double rounding.  */
195*0928368fSKristof Beyls   t2 = mpfr_set (mr, my, r);
196*0928368fSKristof Beyls   if (t2)
197*0928368fSKristof Beyls     t = t2;
198*0928368fSKristof Beyls   mpfr_set_emin (RT(emin));
199*0928368fSKristof Beyls   mpfr_set_emax (RT(emax));
200*0928368fSKristof Beyls   t = mpfr_check_range (mr, t, r);
201*0928368fSKristof Beyls   t = mpfr_subnormalize (mr, t, r);
202*0928368fSKristof Beyls   mpfr_set_emax (MPFR_EMAX_DEFAULT);
203*0928368fSKristof Beyls   mpfr_set_emin (MPFR_EMIN_DEFAULT);
204*0928368fSKristof Beyls   p->y = mpfr_get_d (mr, r);
205*0928368fSKristof Beyls   p->ex = t ? FE_INEXACT : 0;
206*0928368fSKristof Beyls   p->ex_may = FE_INEXACT;
207*0928368fSKristof Beyls   if (mpfr_underflow_p () && (p->ex & FE_INEXACT))
208*0928368fSKristof Beyls     /* TODO: handle before and after rounding uflow cases.  */
209*0928368fSKristof Beyls     p->ex |= FE_UNDERFLOW;
210*0928368fSKristof Beyls   if (mpfr_overflow_p ())
211*0928368fSKristof Beyls     p->ex |= FE_OVERFLOW | FE_INEXACT;
212*0928368fSKristof Beyls   if (mpfr_divby0_p ())
213*0928368fSKristof Beyls     p->ex |= FE_DIVBYZERO;
214*0928368fSKristof Beyls   //if (mpfr_erangeflag_p ())
215*0928368fSKristof Beyls   //  p->ex |= FE_INVALID;
216*0928368fSKristof Beyls   if (!mpfr_nanflag_p () && RT(isok) (ygot, exgot, p->y, p->ex, p->ex_may))
217*0928368fSKristof Beyls     return 1;
218*0928368fSKristof Beyls   if (mpfr_nanflag_p () && !T(qnanpropagation) (a))
219*0928368fSKristof Beyls     p->ex |= FE_INVALID;
220*0928368fSKristof Beyls   p->ulpexp = RT(ulpscale_mpfr) (my, t);
221*0928368fSKristof Beyls   if (!isfinite (p->y))
222*0928368fSKristof Beyls     {
223*0928368fSKristof Beyls       p->tail = 0;
224*0928368fSKristof Beyls       if (isnan (p->y))
225*0928368fSKristof Beyls 	{
226*0928368fSKristof Beyls 	  /* If an input was nan keep its sign.  */
227*0928368fSKristof Beyls 	  p->y = T(sum) (a);
228*0928368fSKristof Beyls 	  if (!isnan (p->y))
229*0928368fSKristof Beyls 	    p->y = (p->y - p->y) / (p->y - p->y);
230*0928368fSKristof Beyls 	  return RT(isok) (ygot, exgot, p->y, p->ex, p->ex_may);
231*0928368fSKristof Beyls 	}
232*0928368fSKristof Beyls       mpfr_set_si_2exp (mr, signbit (p->y) ? -1 : 1, 1024, MPFR_RNDN);
233*0928368fSKristof Beyls       if (mpfr_cmpabs (my, mr) >= 0)
234*0928368fSKristof Beyls 	return RT(isok) (ygot, exgot, p->y, p->ex, p->ex_may);
235*0928368fSKristof Beyls     }
236*0928368fSKristof Beyls   mpfr_sub (me, my, mr, MPFR_RNDN);
237*0928368fSKristof Beyls   mpfr_mul_2si (me, me, -p->ulpexp, MPFR_RNDN);
238*0928368fSKristof Beyls   p->tail = mpfr_get_d (me, MPFR_RNDN);
239*0928368fSKristof Beyls   return 0;
240*0928368fSKristof Beyls #else
241*0928368fSKristof Beyls   abort ();
242*0928368fSKristof Beyls #endif
243*0928368fSKristof Beyls }
244*0928368fSKristof Beyls 
T(cmp)245*0928368fSKristof Beyls static int T(cmp) (const struct fun *f, struct gen *gen,
246*0928368fSKristof Beyls 		     const struct conf *conf)
247*0928368fSKristof Beyls {
248*0928368fSKristof Beyls   double maxerr = 0;
249*0928368fSKristof Beyls   uint64_t cnt = 0;
250*0928368fSKristof Beyls   uint64_t cnt1 = 0;
251*0928368fSKristof Beyls   uint64_t cnt2 = 0;
252*0928368fSKristof Beyls   uint64_t cntfail = 0;
253*0928368fSKristof Beyls   int r = conf->r;
254*0928368fSKristof Beyls   int use_mpfr = conf->mpfr;
255*0928368fSKristof Beyls   int fenv = conf->fenv;
256*0928368fSKristof Beyls   for (;;)
257*0928368fSKristof Beyls     {
258*0928368fSKristof Beyls       struct RT(ret) want;
259*0928368fSKristof Beyls       struct T(args) a = T(next) (gen);
260*0928368fSKristof Beyls       int exgot;
261*0928368fSKristof Beyls       int exgot2;
262*0928368fSKristof Beyls       RT(float) ygot;
263*0928368fSKristof Beyls       RT(float) ygot2;
264*0928368fSKristof Beyls       int fail = 0;
265*0928368fSKristof Beyls       if (fenv)
266*0928368fSKristof Beyls 	T(call_fenv) (f, a, r, &ygot, &exgot);
267*0928368fSKristof Beyls       else
268*0928368fSKristof Beyls 	T(call_nofenv) (f, a, r, &ygot, &exgot);
269*0928368fSKristof Beyls       if (f->twice) {
270*0928368fSKristof Beyls 	secondcall = 1;
271*0928368fSKristof Beyls 	if (fenv)
272*0928368fSKristof Beyls 	  T(call_fenv) (f, a, r, &ygot2, &exgot2);
273*0928368fSKristof Beyls 	else
274*0928368fSKristof Beyls 	  T(call_nofenv) (f, a, r, &ygot2, &exgot2);
275*0928368fSKristof Beyls 	secondcall = 0;
276*0928368fSKristof Beyls 	if (RT(asuint) (ygot) != RT(asuint) (ygot2))
277*0928368fSKristof Beyls 	  {
278*0928368fSKristof Beyls 	    fail = 1;
279*0928368fSKristof Beyls 	    cntfail++;
280*0928368fSKristof Beyls 	    T(printcall) (f, a);
281*0928368fSKristof Beyls 	    printf (" got %a then %a for same input\n", ygot, ygot2);
282*0928368fSKristof Beyls 	  }
283*0928368fSKristof Beyls       }
284*0928368fSKristof Beyls       cnt++;
285*0928368fSKristof Beyls       int ok = use_mpfr
286*0928368fSKristof Beyls 		 ? T(call_mpfr_fix) (f, a, r, &want, ygot, exgot)
287*0928368fSKristof Beyls 		 : (fenv ? T(call_long_fenv) (f, a, r, &want, ygot, exgot)
288*0928368fSKristof Beyls 			 : T(call_long_nofenv) (f, a, r, &want, ygot, exgot));
289*0928368fSKristof Beyls       if (!ok)
290*0928368fSKristof Beyls 	{
291*0928368fSKristof Beyls 	  int print = 0;
292*0928368fSKristof Beyls 	  double err = RT(ulperr) (ygot, &want, r);
293*0928368fSKristof Beyls 	  double abserr = fabs (err);
294*0928368fSKristof Beyls 	  // TODO: count errors below accuracy limit.
295*0928368fSKristof Beyls 	  if (abserr > 0)
296*0928368fSKristof Beyls 	    cnt1++;
297*0928368fSKristof Beyls 	  if (abserr > 1)
298*0928368fSKristof Beyls 	    cnt2++;
299*0928368fSKristof Beyls 	  if (abserr > conf->errlim)
300*0928368fSKristof Beyls 	    {
301*0928368fSKristof Beyls 	      print = 1;
302*0928368fSKristof Beyls 	      if (!fail)
303*0928368fSKristof Beyls 		{
304*0928368fSKristof Beyls 		  fail = 1;
305*0928368fSKristof Beyls 		  cntfail++;
306*0928368fSKristof Beyls 		}
307*0928368fSKristof Beyls 	    }
308*0928368fSKristof Beyls 	  if (abserr > maxerr)
309*0928368fSKristof Beyls 	    {
310*0928368fSKristof Beyls 	      maxerr = abserr;
311*0928368fSKristof Beyls 	      if (!conf->quiet && abserr > conf->softlim)
312*0928368fSKristof Beyls 		print = 1;
313*0928368fSKristof Beyls 	    }
314*0928368fSKristof Beyls 	  if (print)
315*0928368fSKristof Beyls 	    {
316*0928368fSKristof Beyls 	      T(printcall) (f, a);
317*0928368fSKristof Beyls 	      // TODO: inf ulp handling
318*0928368fSKristof Beyls 	      printf (" got %a want %a %+g ulp err %g\n", ygot, want.y,
319*0928368fSKristof Beyls 		      want.tail, err);
320*0928368fSKristof Beyls 	    }
321*0928368fSKristof Beyls 	  int diff = fenv ? exgot ^ want.ex : 0;
322*0928368fSKristof Beyls 	  if (fenv && (diff & ~want.ex_may))
323*0928368fSKristof Beyls 	    {
324*0928368fSKristof Beyls 	      if (!fail)
325*0928368fSKristof Beyls 		{
326*0928368fSKristof Beyls 		  fail = 1;
327*0928368fSKristof Beyls 		  cntfail++;
328*0928368fSKristof Beyls 		}
329*0928368fSKristof Beyls 	      T(printcall) (f, a);
330*0928368fSKristof Beyls 	      printf (" is %a %+g ulp, got except 0x%0x", want.y, want.tail,
331*0928368fSKristof Beyls 		      exgot);
332*0928368fSKristof Beyls 	      if (diff & exgot)
333*0928368fSKristof Beyls 		printf (" wrongly set: 0x%x", diff & exgot);
334*0928368fSKristof Beyls 	      if (diff & ~exgot)
335*0928368fSKristof Beyls 		printf (" wrongly clear: 0x%x", diff & ~exgot);
336*0928368fSKristof Beyls 	      putchar ('\n');
337*0928368fSKristof Beyls 	    }
338*0928368fSKristof Beyls 	}
339*0928368fSKristof Beyls       if (cnt >= conf->n)
340*0928368fSKristof Beyls 	break;
341*0928368fSKristof Beyls       if (!conf->quiet && cnt % 0x100000 == 0)
342*0928368fSKristof Beyls 	printf ("progress: %6.3f%% cnt %llu cnt1 %llu cnt2 %llu cntfail %llu "
343*0928368fSKristof Beyls 		"maxerr %g\n",
344*0928368fSKristof Beyls 		100.0 * cnt / conf->n, (unsigned long long) cnt,
345*0928368fSKristof Beyls 		(unsigned long long) cnt1, (unsigned long long) cnt2,
346*0928368fSKristof Beyls 		(unsigned long long) cntfail, maxerr);
347*0928368fSKristof Beyls     }
348*0928368fSKristof Beyls   double cc = cnt;
349*0928368fSKristof Beyls   if (cntfail)
350*0928368fSKristof Beyls     printf ("FAIL ");
351*0928368fSKristof Beyls   else
352*0928368fSKristof Beyls     printf ("PASS ");
353*0928368fSKristof Beyls   T(printgen) (f, gen);
354*0928368fSKristof Beyls   printf (" round %c errlim %g maxerr %g %s cnt %llu cnt1 %llu %g%% cnt2 %llu "
355*0928368fSKristof Beyls 	  "%g%% cntfail %llu %g%%\n",
356*0928368fSKristof Beyls 	  conf->rc, conf->errlim,
357*0928368fSKristof Beyls 	  maxerr, conf->r == FE_TONEAREST ? "+0.5" : "+1.0",
358*0928368fSKristof Beyls 	  (unsigned long long) cnt,
359*0928368fSKristof Beyls 	  (unsigned long long) cnt1, 100.0 * cnt1 / cc,
360*0928368fSKristof Beyls 	  (unsigned long long) cnt2, 100.0 * cnt2 / cc,
361*0928368fSKristof Beyls 	  (unsigned long long) cntfail, 100.0 * cntfail / cc);
362*0928368fSKristof Beyls   return !!cntfail;
363*0928368fSKristof Beyls }
364