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