Path: blob/main/contrib/arm-optimized-routines/math/aarch64/sve/asinh.c
48375 views
/*1* Double-precision SVE asinh(x) function.2*3* Copyright (c) 2022-2024, Arm Limited.4* SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception5*/67#include "sv_math.h"8#include "test_sig.h"9#include "test_defs.h"1011#define SignMask (0x8000000000000000)12#define One (0x3ff0000000000000)13#define Thres (0x5fe0000000000000) /* asuint64 (0x1p511). */14#define IndexMask (((1 << V_LOG_TABLE_BITS) - 1) << 1)1516static const struct data17{18double even_coeffs[9];19double ln2, p3, p1, p4, p0, p2, c1, c3, c5, c7, c9, c11, c13, c15, c17;20uint64_t off, mask;2122} data = {23/* Polynomial generated using Remez on [2^-26, 1]. */24.even_coeffs ={25-0x1.55555555554a7p-3,26-0x1.6db6db68332e6p-5,27-0x1.6e8b8b654a621p-6,28-0x1.c9871d10885afp-7,29-0x1.3ddca533e9f54p-7,30-0x1.b90c7099dd397p-8,31-0x1.d217026a669ecp-9,32-0x1.e0f37daef9127p-11,33-0x1.021a48685e287p-14, },3435.c1 = 0x1.3333333326c7p-4,36.c3 = 0x1.f1c71b26fb40dp-6,37.c5 = 0x1.1c4daa9e67871p-6,38.c7 = 0x1.7a16e8d9d2ecfp-7,39.c9 = 0x1.0becef748dafcp-7,40.c11 = 0x1.541f2bb1ffe51p-8,41.c13 = 0x1.0b5c7977aaf7p-9,42.c15 = 0x1.388b5fe542a6p-12,43.c17 = 0x1.93d4ba83d34dap-18,4445.ln2 = 0x1.62e42fefa39efp-1,46.p0 = -0x1.ffffffffffff7p-2,47.p1 = 0x1.55555555170d4p-2,48.p2 = -0x1.0000000399c27p-2,49.p3 = 0x1.999b2e90e94cap-3,50.p4 = -0x1.554e550bd501ep-3,51.off = 0x3fe6900900000000,52.mask = 0xfffULL << 52,53};5455static svfloat64_t NOINLINE56special_case (svfloat64_t x, svfloat64_t y, svbool_t special)57{58return sv_call_f64 (asinh, x, y, special);59}6061static inline svfloat64_t62__sv_log_inline (svfloat64_t x, const struct data *d, const svbool_t pg)63{64/* Double-precision SVE log, copied from SVE log implementation with some65cosmetic modification and special-cases removed. See that file for details66of the algorithm used. */6768svuint64_t ix = svreinterpret_u64 (x);69svuint64_t i_off = svsub_x (pg, ix, d->off);70svuint64_t i71= svand_x (pg, svlsr_x (pg, i_off, (51 - V_LOG_TABLE_BITS)), IndexMask);72svuint64_t iz = svsub_x (pg, ix, svand_x (pg, i_off, d->mask));73svfloat64_t z = svreinterpret_f64 (iz);7475svfloat64_t invc = svld1_gather_index (pg, &__v_log_data.table[0].invc, i);76svfloat64_t logc = svld1_gather_index (pg, &__v_log_data.table[0].logc, i);7778svfloat64_t ln2_p3 = svld1rq (svptrue_b64 (), &d->ln2);79svfloat64_t p1_p4 = svld1rq (svptrue_b64 (), &d->p1);8081svfloat64_t r = svmla_x (pg, sv_f64 (-1.0), invc, z);82svfloat64_t kd83= svcvt_f64_x (pg, svasr_x (pg, svreinterpret_s64 (i_off), 52));8485svfloat64_t hi = svmla_lane (svadd_x (pg, logc, r), kd, ln2_p3, 0);86svfloat64_t r2 = svmul_x (svptrue_b64 (), r, r);87svfloat64_t y = svmla_lane (sv_f64 (d->p2), r, ln2_p3, 1);88svfloat64_t p = svmla_lane (sv_f64 (d->p0), r, p1_p4, 0);8990y = svmla_lane (y, r2, p1_p4, 1);91y = svmla_x (pg, p, r2, y);92y = svmla_x (pg, hi, r2, y);93return y;94}9596/* Double-precision implementation of SVE asinh(x).97asinh is very sensitive around 1, so it is impractical to devise a single98low-cost algorithm which is sufficiently accurate on a wide range of input.99Instead we use two different algorithms:100asinh(x) = sign(x) * log(|x| + sqrt(x^2 + 1) if |x| >= 1101= sign(x) * (|x| + |x|^3 * P(x^2)) otherwise102where log(x) is an optimized log approximation, and P(x) is a polynomial103shared with the scalar routine. The greatest observed error 2.51 ULP, in104|x| >= 1:105_ZGVsMxv_asinh(0x1.170469d024505p+0) got 0x1.e3181c43b0f36p-1106want 0x1.e3181c43b0f39p-1. */107svfloat64_t SV_NAME_D1 (asinh) (svfloat64_t x, const svbool_t pg)108{109const struct data *d = ptr_barrier (&data);110111svuint64_t ix = svreinterpret_u64 (x);112svuint64_t iax = svbic_x (pg, ix, SignMask);113svuint64_t sign = svand_x (pg, ix, SignMask);114svfloat64_t ax = svreinterpret_f64 (iax);115svbool_t ge1 = svcmpge (pg, iax, One);116svbool_t special = svcmpge (pg, iax, Thres);117118/* Option 1: |x| >= 1.119Compute asinh(x) according by asinh(x) = log(x + sqrt(x^2 + 1)). */120svfloat64_t option_1 = sv_f64 (0);121if (likely (svptest_any (pg, ge1)))122{123svfloat64_t x2 = svmul_x (svptrue_b64 (), ax, ax);124option_1 = __sv_log_inline (125svadd_x (pg, ax, svsqrt_x (pg, svadd_x (pg, x2, 1))), d, pg);126}127128/* Option 2: |x| < 1.129Compute asinh(x) using a polynomial.130The largest observed error in this region is 1.51 ULPs:131_ZGVsMxv_asinh(0x1.fe12bf8c616a2p-1) got 0x1.c1e649ee2681bp-1132want 0x1.c1e649ee2681dp-1. */133134svfloat64_t option_2 = sv_f64 (0);135if (likely (svptest_any (pg, svnot_z (pg, ge1))))136{137svfloat64_t x2 = svmul_x (svptrue_b64 (), ax, ax);138svfloat64_t x4 = svmul_x (svptrue_b64 (), x2, x2);139/* Order-17 Pairwise Horner scheme. */140svfloat64_t c13 = svld1rq (svptrue_b64 (), &d->c1);141svfloat64_t c57 = svld1rq (svptrue_b64 (), &d->c5);142svfloat64_t c911 = svld1rq (svptrue_b64 (), &d->c9);143svfloat64_t c1315 = svld1rq (svptrue_b64 (), &d->c13);144145svfloat64_t p01 = svmla_lane (sv_f64 (d->even_coeffs[0]), x2, c13, 0);146svfloat64_t p23 = svmla_lane (sv_f64 (d->even_coeffs[1]), x2, c13, 1);147svfloat64_t p45 = svmla_lane (sv_f64 (d->even_coeffs[2]), x2, c57, 0);148svfloat64_t p67 = svmla_lane (sv_f64 (d->even_coeffs[3]), x2, c57, 1);149svfloat64_t p89 = svmla_lane (sv_f64 (d->even_coeffs[4]), x2, c911, 0);150svfloat64_t p1011 = svmla_lane (sv_f64 (d->even_coeffs[5]), x2, c911, 1);151svfloat64_t p1213152= svmla_lane (sv_f64 (d->even_coeffs[6]), x2, c1315, 0);153svfloat64_t p1415154= svmla_lane (sv_f64 (d->even_coeffs[7]), x2, c1315, 1);155svfloat64_t p1617 = svmla_x (pg, sv_f64 (d->even_coeffs[8]), x2, d->c17);156157svfloat64_t p = svmla_x (pg, p1415, x4, p1617);158p = svmla_x (pg, p1213, x4, p);159p = svmla_x (pg, p1011, x4, p);160p = svmla_x (pg, p89, x4, p);161162p = svmla_x (pg, p67, x4, p);163p = svmla_x (pg, p45, x4, p);164165p = svmla_x (pg, p23, x4, p);166167p = svmla_x (pg, p01, x4, p);168169option_2 = svmla_x (pg, ax, p, svmul_x (svptrue_b64 (), x2, ax));170}171172if (unlikely (svptest_any (pg, special)))173return special_case (174x,175svreinterpret_f64 (sveor_x (176pg, svreinterpret_u64 (svsel (ge1, option_1, option_2)), sign)),177special);178179/* Choose the right option for each lane. */180svfloat64_t y = svsel (ge1, option_1, option_2);181return svreinterpret_f64 (sveor_x (pg, svreinterpret_u64 (y), sign));182}183184TEST_SIG (SV, D, 1, asinh, -10.0, 10.0)185TEST_ULP (SV_NAME_D1 (asinh), 2.52)186TEST_DISABLE_FENV (SV_NAME_D1 (asinh))187TEST_SYM_INTERVAL (SV_NAME_D1 (asinh), 0, 0x1p-26, 50000)188TEST_SYM_INTERVAL (SV_NAME_D1 (asinh), 0x1p-26, 1, 50000)189TEST_SYM_INTERVAL (SV_NAME_D1 (asinh), 1, 0x1p511, 50000)190TEST_SYM_INTERVAL (SV_NAME_D1 (asinh), 0x1p511, inf, 40000)191/* Test vector asinh 3 times, with control lane < 1, > 1 and special.192Ensures the v_sel is choosing the right option in all cases. */193TEST_CONTROL_VALUE (SV_NAME_D1 (asinh), 0.5)194TEST_CONTROL_VALUE (SV_NAME_D1 (asinh), 2)195TEST_CONTROL_VALUE (SV_NAME_D1 (asinh), 0x1p600)196CLOSE_SVE_ATTR197198199