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