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