Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/arm-optimized-routines/math/aarch64/advsimd/exp10.c
48375 views
1
/*
2
* Double-precision vector 10^x function.
3
*
4
* Copyright (c) 2023-2024, Arm Limited.
5
* SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6
*/
7
8
#define _GNU_SOURCE
9
#include "mathlib.h"
10
#include "v_math.h"
11
#include "test_sig.h"
12
#include "test_defs.h"
13
14
/* Value of |x| above which scale overflows without special treatment. */
15
#define SpecialBound 306.0 /* floor (log10 (2^1023)) - 1. */
16
/* Value of n above which scale overflows even with special treatment. */
17
#define ScaleBound 163840.0 /* 1280.0 * N. */
18
19
const static struct data
20
{
21
float64x2_t poly[4];
22
float64x2_t log10_2, log2_10_hi, log2_10_lo, shift;
23
#if !WANT_SIMD_EXCEPT
24
float64x2_t special_bound, scale_thresh;
25
#endif
26
} data = {
27
/* Coefficients generated using Remez algorithm.
28
rel error: 0x1.5ddf8f28p-54
29
abs error: 0x1.5ed266c8p-54 in [ -log10(2)/256, log10(2)/256 ]
30
maxerr: 1.14432 +0.5 ulp. */
31
.poly = { V2 (0x1.26bb1bbb5524p1), V2 (0x1.53524c73cecdap1),
32
V2 (0x1.047060efb781cp1), V2 (0x1.2bd76040f0d16p0) },
33
.log10_2 = V2 (0x1.a934f0979a371p8), /* N/log2(10). */
34
.log2_10_hi = V2 (0x1.34413509f79ffp-9), /* log2(10)/N. */
35
.log2_10_lo = V2 (-0x1.9dc1da994fd21p-66),
36
.shift = V2 (0x1.8p+52),
37
#if !WANT_SIMD_EXCEPT
38
.scale_thresh = V2 (ScaleBound),
39
.special_bound = V2 (SpecialBound),
40
#endif
41
};
42
43
#define N (1 << V_EXP_TABLE_BITS)
44
#define IndexMask v_u64 (N - 1)
45
46
#if WANT_SIMD_EXCEPT
47
48
# define TinyBound v_u64 (0x2000000000000000) /* asuint64 (0x1p-511). */
49
# define BigBound v_u64 (0x4070000000000000) /* asuint64 (0x1p8). */
50
# define Thres v_u64 (0x2070000000000000) /* BigBound - TinyBound. */
51
52
static float64x2_t VPCS_ATTR NOINLINE
53
special_case (float64x2_t x, float64x2_t y, uint64x2_t cmp)
54
{
55
/* If fenv exceptions are to be triggered correctly, fall back to the scalar
56
routine for special lanes. */
57
return v_call_f64 (exp10, x, y, cmp);
58
}
59
60
#else
61
62
# define SpecialOffset v_u64 (0x6000000000000000) /* 0x1p513. */
63
/* SpecialBias1 + SpecialBias1 = asuint(1.0). */
64
# define SpecialBias1 v_u64 (0x7000000000000000) /* 0x1p769. */
65
# define SpecialBias2 v_u64 (0x3010000000000000) /* 0x1p-254. */
66
67
static inline float64x2_t VPCS_ATTR
68
special_case (float64x2_t s, float64x2_t y, float64x2_t n,
69
const struct data *d)
70
{
71
/* 2^(n/N) may overflow, break it up into s1*s2. */
72
uint64x2_t b = vandq_u64 (vcltzq_f64 (n), SpecialOffset);
73
float64x2_t s1 = vreinterpretq_f64_u64 (vsubq_u64 (SpecialBias1, b));
74
float64x2_t s2 = vreinterpretq_f64_u64 (
75
vaddq_u64 (vsubq_u64 (vreinterpretq_u64_f64 (s), SpecialBias2), b));
76
uint64x2_t cmp = vcagtq_f64 (n, d->scale_thresh);
77
float64x2_t r1 = vmulq_f64 (s1, s1);
78
float64x2_t r0 = vmulq_f64 (vfmaq_f64 (s2, y, s2), s1);
79
return vbslq_f64 (cmp, r1, r0);
80
}
81
82
#endif
83
84
/* Fast vector implementation of exp10.
85
Maximum measured error is 1.64 ulp.
86
_ZGVnN2v_exp10(0x1.ccd1c9d82cc8cp+0) got 0x1.f8dab6d7fed0cp+5
87
want 0x1.f8dab6d7fed0ap+5. */
88
float64x2_t VPCS_ATTR V_NAME_D1 (exp10) (float64x2_t x)
89
{
90
const struct data *d = ptr_barrier (&data);
91
uint64x2_t cmp;
92
#if WANT_SIMD_EXCEPT
93
/* If any lanes are special, mask them with 1 and retain a copy of x to allow
94
special_case to fix special lanes later. This is only necessary if fenv
95
exceptions are to be triggered correctly. */
96
float64x2_t xm = x;
97
uint64x2_t iax = vreinterpretq_u64_f64 (vabsq_f64 (x));
98
cmp = vcgeq_u64 (vsubq_u64 (iax, TinyBound), Thres);
99
if (unlikely (v_any_u64 (cmp)))
100
x = vbslq_f64 (cmp, v_f64 (1), x);
101
#else
102
cmp = vcageq_f64 (x, d->special_bound);
103
#endif
104
105
/* n = round(x/(log10(2)/N)). */
106
float64x2_t z = vfmaq_f64 (d->shift, x, d->log10_2);
107
uint64x2_t u = vreinterpretq_u64_f64 (z);
108
float64x2_t n = vsubq_f64 (z, d->shift);
109
110
/* r = x - n*log10(2)/N. */
111
float64x2_t r = x;
112
r = vfmsq_f64 (r, d->log2_10_hi, n);
113
r = vfmsq_f64 (r, d->log2_10_lo, n);
114
115
uint64x2_t e = vshlq_n_u64 (u, 52 - V_EXP_TABLE_BITS);
116
uint64x2_t i = vandq_u64 (u, IndexMask);
117
118
/* y = exp10(r) - 1 ~= C0 r + C1 r^2 + C2 r^3 + C3 r^4. */
119
float64x2_t r2 = vmulq_f64 (r, r);
120
float64x2_t p = vfmaq_f64 (d->poly[0], r, d->poly[1]);
121
float64x2_t y = vfmaq_f64 (d->poly[2], r, d->poly[3]);
122
p = vfmaq_f64 (p, y, r2);
123
y = vmulq_f64 (r, p);
124
125
/* s = 2^(n/N). */
126
u = v_lookup_u64 (__v_exp_data, i);
127
float64x2_t s = vreinterpretq_f64_u64 (vaddq_u64 (u, e));
128
129
if (unlikely (v_any_u64 (cmp)))
130
#if WANT_SIMD_EXCEPT
131
return special_case (xm, vfmaq_f64 (s, y, s), cmp);
132
#else
133
return special_case (s, y, n, d);
134
#endif
135
136
return vfmaq_f64 (s, y, s);
137
}
138
139
#if WANT_EXP10_TESTS
140
TEST_SIG (S, D, 1, exp10, -9.9, 9.9)
141
TEST_SIG (V, D, 1, exp10, -9.9, 9.9)
142
TEST_ULP (V_NAME_D1 (exp10), 1.15)
143
TEST_DISABLE_FENV_IF_NOT (V_NAME_D1 (exp10), WANT_SIMD_EXCEPT)
144
TEST_SYM_INTERVAL (V_NAME_D1 (exp10), 0, SpecialBound, 5000)
145
TEST_SYM_INTERVAL (V_NAME_D1 (exp10), SpecialBound, ScaleBound, 5000)
146
TEST_SYM_INTERVAL (V_NAME_D1 (exp10), ScaleBound, inf, 10000)
147
#endif
148
149