Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/arm-optimized-routines/math/aarch64/sve/expm1f.c
48375 views
1
/*
2
* Single-precision vector exp(x) - 1 function.
3
*
4
* Copyright (c) 2023-2024, Arm Limited.
5
* SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6
*/
7
8
#include "sv_math.h"
9
#include "test_sig.h"
10
#include "test_defs.h"
11
12
/* Largest value of x for which expm1(x) should round to -1. */
13
#define SpecialBound 0x1.5ebc4p+6f
14
15
static const struct data
16
{
17
/* These 4 are grouped together so they can be loaded as one quadword, then
18
used with _lane forms of svmla/svmls. */
19
float c2, c4, ln2_hi, ln2_lo;
20
float c0, inv_ln2, c1, c3, special_bound;
21
} data = {
22
/* Generated using fpminimax. */
23
.c0 = 0x1.fffffep-2, .c1 = 0x1.5554aep-3,
24
.c2 = 0x1.555736p-5, .c3 = 0x1.12287cp-7,
25
.c4 = 0x1.6b55a2p-10, .inv_ln2 = 0x1.715476p+0f,
26
.special_bound = SpecialBound, .ln2_lo = 0x1.7f7d1cp-20f,
27
.ln2_hi = 0x1.62e4p-1f,
28
29
};
30
31
static svfloat32_t NOINLINE
32
special_case (svfloat32_t x, svbool_t pg)
33
{
34
return sv_call_f32 (expm1f, x, x, pg);
35
}
36
37
/* Single-precision SVE exp(x) - 1. Maximum error is 1.52 ULP:
38
_ZGVsMxv_expm1f(0x1.8f4ebcp-2) got 0x1.e859dp-2
39
want 0x1.e859d4p-2. */
40
svfloat32_t SV_NAME_F1 (expm1) (svfloat32_t x, svbool_t pg)
41
{
42
const struct data *d = ptr_barrier (&data);
43
44
/* Large, NaN/Inf. */
45
svbool_t special = svnot_z (pg, svaclt (pg, x, d->special_bound));
46
47
if (unlikely (svptest_any (pg, special)))
48
return special_case (x, pg);
49
50
/* This vector is reliant on layout of data - it contains constants
51
that can be used with _lane forms of svmla/svmls. Values are:
52
[ coeff_2, coeff_4, ln2_hi, ln2_lo ]. */
53
svfloat32_t lane_constants = svld1rq (svptrue_b32 (), &d->c2);
54
55
/* Reduce argument to smaller range:
56
Let i = round(x / ln2)
57
and f = x - i * ln2, then f is in [-ln2/2, ln2/2].
58
exp(x) - 1 = 2^i * (expm1(f) + 1) - 1
59
where 2^i is exact because i is an integer. */
60
svfloat32_t j = svmul_x (svptrue_b32 (), x, d->inv_ln2);
61
j = svrinta_x (pg, j);
62
63
svfloat32_t f = svmls_lane (x, j, lane_constants, 2);
64
f = svmls_lane (f, j, lane_constants, 3);
65
66
/* Approximate expm1(f) using polynomial.
67
Taylor expansion for expm1(x) has the form:
68
x + ax^2 + bx^3 + cx^4 ....
69
So we calculate the polynomial P(f) = a + bf + cf^2 + ...
70
and assemble the approximation expm1(f) ~= f + f^2 * P(f). */
71
svfloat32_t p12 = svmla_lane (sv_f32 (d->c1), f, lane_constants, 0);
72
svfloat32_t p34 = svmla_lane (sv_f32 (d->c3), f, lane_constants, 1);
73
svfloat32_t f2 = svmul_x (svptrue_b32 (), f, f);
74
svfloat32_t p = svmla_x (pg, p12, f2, p34);
75
76
p = svmla_x (pg, sv_f32 (d->c0), f, p);
77
p = svmla_x (pg, f, f2, p);
78
79
/* Assemble the result.
80
expm1(x) ~= 2^i * (p + 1) - 1
81
Let t = 2^i. */
82
svfloat32_t t = svscale_x (pg, sv_f32 (1.0f), svcvt_s32_x (pg, j));
83
return svmla_x (pg, svsub_x (pg, t, 1.0f), p, t);
84
}
85
86
TEST_SIG (SV, F, 1, expm1, -9.9, 9.9)
87
TEST_ULP (SV_NAME_F1 (expm1), 1.02)
88
TEST_DISABLE_FENV (SV_NAME_F1 (expm1))
89
TEST_SYM_INTERVAL (SV_NAME_F1 (expm1), 0, SpecialBound, 100000)
90
TEST_SYM_INTERVAL (SV_NAME_F1 (expm1), SpecialBound, inf, 1000)
91
CLOSE_SVE_ATTR
92
93