aboutsummaryrefslogtreecommitdiff
path: root/pl/math/math_config.h
blob: 81da8630835292e945e7fe6e7096338e08d74e0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
/*
 * Configuration for math routines.
 *
 * Copyright (c) 2017-2022, Arm Limited.
 * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
 */

#ifndef _MATH_CONFIG_H
#define _MATH_CONFIG_H

#include <math.h>
#include <stdint.h>

#ifndef WANT_ROUNDING
/* If defined to 1, return correct results for special cases in non-nearest
   rounding modes (logf (1.0f) returns 0.0f with FE_DOWNWARD rather than -0.0f).
   This may be set to 0 if there is no fenv support or if math functions only
   get called in round to nearest mode.  */
# define WANT_ROUNDING 1
#endif
#ifndef WANT_ERRNO
/* If defined to 1, set errno in math functions according to ISO C.  Many math
   libraries do not set errno, so this is 0 by default.  It may need to be
   set to 1 if math.h has (math_errhandling & MATH_ERRNO) != 0.  */
# define WANT_ERRNO 0
#endif

/* Compiler can inline round as a single instruction.  */
#ifndef HAVE_FAST_ROUND
# if __aarch64__
#   define HAVE_FAST_ROUND 1
# else
#   define HAVE_FAST_ROUND 0
# endif
#endif

/* Compiler can inline lround, but not (long)round(x).  */
#ifndef HAVE_FAST_LROUND
# if __aarch64__ && (100*__GNUC__ + __GNUC_MINOR__) >= 408 && __NO_MATH_ERRNO__
#   define HAVE_FAST_LROUND 1
# else
#   define HAVE_FAST_LROUND 0
# endif
#endif

/* Compiler can inline fma as a single instruction.  */
#ifndef HAVE_FAST_FMA
# if defined FP_FAST_FMA || __aarch64__
#   define HAVE_FAST_FMA 1
# else
#   define HAVE_FAST_FMA 0
# endif
#endif

/* Provide *_finite symbols and some of the glibc hidden symbols
   so libmathlib can be used with binaries compiled against glibc
   to interpose math functions with both static and dynamic linking.  */
#ifndef USE_GLIBC_ABI
# if __GNUC__
#   define USE_GLIBC_ABI 1
# else
#   define USE_GLIBC_ABI 0
# endif
#endif

/* Optionally used extensions.  */
#ifdef __GNUC__
# define HIDDEN __attribute__ ((__visibility__ ("hidden")))
# define NOINLINE __attribute__ ((noinline))
# define UNUSED __attribute__ ((unused))
# define likely(x) __builtin_expect (!!(x), 1)
# define unlikely(x) __builtin_expect (x, 0)
# if __GNUC__ >= 9
#   define attribute_copy(f) __attribute__ ((copy (f)))
# else
#   define attribute_copy(f)
# endif
# define strong_alias(f, a) \
  extern __typeof (f) a __attribute__ ((alias (#f))) attribute_copy (f);
# define hidden_alias(f, a) \
  extern __typeof (f) a __attribute__ ((alias (#f), visibility ("hidden"))) \
  attribute_copy (f);
#else
# define HIDDEN
# define NOINLINE
# define UNUSED
# define likely(x) (x)
# define unlikely(x) (x)
#endif

#if HAVE_FAST_ROUND
/* When set, the roundtoint and converttoint functions are provided with
   the semantics documented below.  */
# define TOINT_INTRINSICS 1

/* Round x to nearest int in all rounding modes, ties have to be rounded
   consistently with converttoint so the results match.  If the result
   would be outside of [-2^31, 2^31-1] then the semantics is unspecified.  */
static inline double_t
roundtoint (double_t x)
{
  return round (x);
}

/* Convert x to nearest int in all rounding modes, ties have to be rounded
   consistently with roundtoint.  If the result is not representible in an
   int32_t then the semantics is unspecified.  */
static inline int32_t
converttoint (double_t x)
{
# if HAVE_FAST_LROUND
  return lround (x);
# else
  return (long) round (x);
# endif
}
#endif

static inline uint32_t
asuint (float f)
{
  union
  {
    float f;
    uint32_t i;
  } u = {f};
  return u.i;
}

static inline float
asfloat (uint32_t i)
{
  union
  {
    uint32_t i;
    float f;
  } u = {i};
  return u.f;
}

static inline uint64_t
asuint64 (double f)
{
  union
  {
    double f;
    uint64_t i;
  } u = {f};
  return u.i;
}

static inline double
asdouble (uint64_t i)
{
  union
  {
    uint64_t i;
    double f;
  } u = {i};
  return u.f;
}

#ifndef IEEE_754_2008_SNAN
# define IEEE_754_2008_SNAN 1
#endif
static inline int
issignalingf_inline (float x)
{
  uint32_t ix = asuint (x);
  if (!IEEE_754_2008_SNAN)
    return (ix & 0x7fc00000) == 0x7fc00000;
  return 2 * (ix ^ 0x00400000) > 2u * 0x7fc00000;
}

static inline int
issignaling_inline (double x)
{
  uint64_t ix = asuint64 (x);
  if (!IEEE_754_2008_SNAN)
    return (ix & 0x7ff8000000000000) == 0x7ff8000000000000;
  return 2 * (ix ^ 0x0008000000000000) > 2 * 0x7ff8000000000000ULL;
}

#if __aarch64__ && __GNUC__
/* Prevent the optimization of a floating-point expression.  */
static inline float
opt_barrier_float (float x)
{
  __asm__ __volatile__ ("" : "+w" (x));
  return x;
}
static inline double
opt_barrier_double (double x)
{
  __asm__ __volatile__ ("" : "+w" (x));
  return x;
}
/* Force the evaluation of a floating-point expression for its side-effect.  */
static inline void
force_eval_float (float x)
{
  __asm__ __volatile__ ("" : "+w" (x));
}
static inline void
force_eval_double (double x)
{
  __asm__ __volatile__ ("" : "+w" (x));
}
#else
static inline float
opt_barrier_float (float x)
{
  volatile float y = x;
  return y;
}
static inline double
opt_barrier_double (double x)
{
  volatile double y = x;
  return y;
}
static inline void
force_eval_float (float x)
{
  volatile float y UNUSED = x;
}
static inline void
force_eval_double (double x)
{
  volatile double y UNUSED = x;
}
#endif

/* Evaluate an expression as the specified type, normally a type
   cast should be enough, but compilers implement non-standard
   excess-precision handling, so when FLT_EVAL_METHOD != 0 then
   these functions may need to be customized.  */
static inline float
eval_as_float (float x)
{
  return x;
}
static inline double
eval_as_double (double x)
{
  return x;
}

/* Error handling tail calls for special cases, with a sign argument.
   The sign of the return value is set if the argument is non-zero.  */

/* The result overflows.  */
HIDDEN float __math_oflowf (uint32_t);
/* The result underflows to 0 in nearest rounding mode.  */
HIDDEN float __math_uflowf (uint32_t);
/* The result underflows to 0 in some directed rounding mode only.  */
HIDDEN float __math_may_uflowf (uint32_t);
/* Division by zero.  */
HIDDEN float __math_divzerof (uint32_t);
/* The result overflows.  */
HIDDEN double __math_oflow (uint32_t);
/* The result underflows to 0 in nearest rounding mode.  */
HIDDEN double __math_uflow (uint32_t);
/* The result underflows to 0 in some directed rounding mode only.  */
HIDDEN double __math_may_uflow (uint32_t);
/* Division by zero.  */
HIDDEN double __math_divzero (uint32_t);

/* Error handling using input checking.  */

/* Invalid input unless it is a quiet NaN.  */
HIDDEN float __math_invalidf (float);
/* Invalid input unless it is a quiet NaN.  */
HIDDEN double __math_invalid (double);

/* Error handling using output checking, only for errno setting.  */

/* Check if the result overflowed to infinity.  */
HIDDEN double __math_check_oflow (double);
/* Check if the result underflowed to 0.  */
HIDDEN double __math_check_uflow (double);

/* Check if the result overflowed to infinity.  */
static inline double
check_oflow (double x)
{
  return WANT_ERRNO ? __math_check_oflow (x) : x;
}

/* Check if the result underflowed to 0.  */
static inline double
check_uflow (double x)
{
  return WANT_ERRNO ? __math_check_uflow (x) : x;
}

/* Check if the result overflowed to infinity.  */
HIDDEN float __math_check_oflowf (float);
/* Check if the result underflowed to 0.  */
HIDDEN float __math_check_uflowf (float);

/* Check if the result overflowed to infinity.  */
static inline float
check_oflowf (float x)
{
  return WANT_ERRNO ? __math_check_oflowf (x) : x;
}

/* Check if the result underflowed to 0.  */
static inline float
check_uflowf (float x)
{
  return WANT_ERRNO ? __math_check_uflowf (x) : x;
}

extern const struct erff_data
{
  float erff_poly_A[6];
  float erff_poly_B[7];
} __erff_data HIDDEN;

/* Data for logf and log10f.  */
#define LOGF_TABLE_BITS 4
#define LOGF_POLY_ORDER 4
extern const struct logf_data
{
  struct
  {
    double invc, logc;
  } tab[1 << LOGF_TABLE_BITS];
  double ln2;
  double invln10;
  double poly[LOGF_POLY_ORDER - 1]; /* First order coefficient is 1.  */
} __logf_data HIDDEN;

/* Data for low accuracy log10 (with 1/ln(10) included in coefficients).  */
#define LOG10_TABLE_BITS 7
#define LOG10_POLY_ORDER 6
#define LOG10_POLY1_ORDER 12
extern const struct log10_data
{
  double ln2hi;
  double ln2lo;
  double invln10;
  double poly[LOG10_POLY_ORDER - 1]; /* First coefficient is 1/log(10).  */
  double poly1[LOG10_POLY1_ORDER - 1];
  struct {double invc, logc;} tab[1 << LOG10_TABLE_BITS];
#if !HAVE_FAST_FMA
  struct {double chi, clo;} tab2[1 << LOG10_TABLE_BITS];
#endif
} __log10_data HIDDEN;

#define EXP_TABLE_BITS 7
#define EXP_POLY_ORDER 5
/* Use polynomial that is optimized for a wider input range.  This may be
   needed for good precision in non-nearest rounding and !TOINT_INTRINSICS.  */
#define EXP_POLY_WIDE 0
/* Use close to nearest rounding toint when !TOINT_INTRINSICS.  This may be
   needed for good precision in non-nearest rouning and !EXP_POLY_WIDE.  */
#define EXP_USE_TOINT_NARROW 0
#define EXP2_POLY_ORDER 5
#define EXP2_POLY_WIDE 0
extern const struct exp_data
{
  double invln2N;
  double shift;
  double negln2hiN;
  double negln2loN;
  double poly[4]; /* Last four coefficients.  */
  double exp2_shift;
  double exp2_poly[EXP2_POLY_ORDER];
  uint64_t tab[2*(1 << EXP_TABLE_BITS)];
} __exp_data HIDDEN;

#define ERFC_NUM_INTERVALS 20
#define ERFC_POLY_ORDER 12
extern const struct erfc_data
{
  double interval_bounds[ERFC_NUM_INTERVALS + 1];
  double poly[ERFC_NUM_INTERVALS][ERFC_POLY_ORDER + 1];
} __erfc_data HIDDEN;
extern const struct v_erfc_data
{
  double interval_bounds[ERFC_NUM_INTERVALS + 1];
  double poly[ERFC_NUM_INTERVALS + 1][ERFC_POLY_ORDER + 1];
}  __v_erfc_data HIDDEN;

#define ERFCF_POLY_NCOEFFS 16
extern const struct erfcf_poly_data
{
  double poly[4][ERFCF_POLY_NCOEFFS];
} __erfcf_poly_data HIDDEN;

#define V_EXP_TAIL_TABLE_BITS 8
extern const uint64_t __v_exp_tail_data[1 << V_EXP_TAIL_TABLE_BITS] HIDDEN;

#define V_ERF_NINTS 49
#define V_ERF_NCOEFFS 10
extern const struct v_erf_data
{
  double shifts[V_ERF_NINTS];
  double coeffs[V_ERF_NCOEFFS][V_ERF_NINTS];
} __v_erf_data HIDDEN;

#define V_ERFF_NCOEFFS 7
extern const struct v_erff_data
{
  float coeffs[V_ERFF_NCOEFFS][2];
} __v_erff_data HIDDEN;

#define ATAN_POLY_NCOEFFS 20
extern const struct atan_poly_data
{
  double poly[ATAN_POLY_NCOEFFS];
} __atan_poly_data HIDDEN;

#define ATANF_POLY_NCOEFFS 8
extern const struct atanf_poly_data
{
  float poly[ATANF_POLY_NCOEFFS];
} __atanf_poly_data HIDDEN;

#define ASINHF_NCOEFFS 8
extern const struct asinhf_data
{
  float coeffs[ASINHF_NCOEFFS];
} __asinhf_data HIDDEN;

#define LOG_TABLE_BITS 7
#define LOG_POLY_ORDER 6
#define LOG_POLY1_ORDER 12
extern const struct log_data
{
  double ln2hi;
  double ln2lo;
  double poly[LOG_POLY_ORDER - 1]; /* First coefficient is 1.  */
  double poly1[LOG_POLY1_ORDER - 1];
  struct
  {
    double invc, logc;
  } tab[1 << LOG_TABLE_BITS];
#if !HAVE_FAST_FMA
  struct
  {
    double chi, clo;
  } tab2[1 << LOG_TABLE_BITS];
#endif
} __log_data HIDDEN;

#define ASINH_NCOEFFS 18
extern const struct asinh_data
{
  double poly[ASINH_NCOEFFS];
} __asinh_data HIDDEN;

#define LOG1P_NCOEFFS 19
extern const struct log1p_data
{
  double coeffs[LOG1P_NCOEFFS];
} __log1p_data HIDDEN;

#define LOG1PF_2U5
#define V_LOG1PF_2U5
#define LOG1PF_NCOEFFS 9
extern const struct log1pf_data
{
  float coeffs[LOG1PF_NCOEFFS];
} __log1pf_data HIDDEN;

#define TANF_P_POLY_NCOEFFS 7
/* cotan approach needs order 3 on [0, pi/4] to reach <3.5ulps.  */
#define TANF_Q_POLY_NCOEFFS 4
extern const struct tanf_poly_data
{
  float poly_tan[TANF_P_POLY_NCOEFFS];
  float poly_cotan[TANF_Q_POLY_NCOEFFS];
} __tanf_poly_data HIDDEN;

#define V_LOG2F_POLY_NCOEFFS 9
extern const struct v_log2f_data
{
  float poly[V_LOG2F_POLY_NCOEFFS];
} __v_log2f_data HIDDEN;

#define V_LOG2_TABLE_BITS 7
#define V_LOG2_POLY_ORDER 6
extern const struct v_log2_data
{
  double poly[V_LOG2_POLY_ORDER - 1];
  struct
  {
    double invc, log2c;
  } tab[1 << V_LOG2_TABLE_BITS];
} __v_log2_data HIDDEN;

#define V_SINF_NCOEFFS 4
extern const struct sv_sinf_data
{
  float coeffs[V_SINF_NCOEFFS];
} __sv_sinf_data HIDDEN;

#define V_LOG10_TABLE_BITS 7
#define V_LOG10_POLY_ORDER 6
extern const struct v_log10_data
{
  struct
  {
    double invc, log10c;
  } tab[1 << V_LOG10_TABLE_BITS];
  double poly[V_LOG10_POLY_ORDER - 1];
  double invln10, log10_2;
} __v_log10_data HIDDEN;

#define V_LOG10F_POLY_ORDER 9
extern const float __v_log10f_poly[V_LOG10F_POLY_ORDER - 1] HIDDEN;

#define SV_LOGF_POLY_ORDER 8
extern const float __sv_logf_poly[SV_LOGF_POLY_ORDER - 1] HIDDEN;

#define SV_LOG_POLY_ORDER 6
#define SV_LOG_TABLE_BITS 7
extern const struct sv_log_data
{
  double invc[1 << SV_LOG_TABLE_BITS];
  double logc[1 << SV_LOG_TABLE_BITS];
  double poly[SV_LOG_POLY_ORDER - 1];
} __sv_log_data HIDDEN;

#ifndef SV_EXPF_USE_FEXPA
#define SV_EXPF_USE_FEXPA 0
#endif
#define SV_EXPF_POLY_ORDER 6
extern const float __sv_expf_poly[SV_EXPF_POLY_ORDER - 1] HIDDEN;

#define EXPM1F_POLY_ORDER 5
extern const float __expm1f_poly[EXPM1F_POLY_ORDER] HIDDEN;

#define EXPF_TABLE_BITS 5
#define EXPF_POLY_ORDER 3
extern const struct expf_data
{
  uint64_t tab[1 << EXPF_TABLE_BITS];
  double invln2_scaled;
  double poly_scaled[EXPF_POLY_ORDER];
} __expf_data HIDDEN;

#define EXPM1_POLY_ORDER 11
extern const double __expm1_poly[EXPM1_POLY_ORDER] HIDDEN;

extern const struct cbrtf_data
{
  float poly[4];
  float table[5];
} __cbrtf_data HIDDEN;

#endif