Path: blob/main/contrib/arm-optimized-routines/math/aarch64/sve/cbrt.c
48375 views
/*1* Double-precision SVE cbrt(x) function.2*3* Copyright (c) 2023-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"10#include "sv_poly_f64.h"1112const static struct data13{14float64_t poly[4];15float64_t table[5];16float64_t one_third, two_thirds, shift;17int64_t exp_bias;18uint64_t tiny_bound, thresh;19} data = {20/* Generated with FPMinimax in [0.5, 1]. */21.poly = { 0x1.c14e8ee44767p-2, 0x1.dd2d3f99e4c0ep-1, -0x1.08e83026b7e74p-1,220x1.2c74eaa3ba428p-3, },23/* table[i] = 2^((i - 2) / 3). */24.table = { 0x1.428a2f98d728bp-1, 0x1.965fea53d6e3dp-1, 0x1p0,250x1.428a2f98d728bp0, 0x1.965fea53d6e3dp0, },26.one_third = 0x1.5555555555555p-2,27.two_thirds = 0x1.5555555555555p-1,28.shift = 0x1.8p52,29.exp_bias = 1022,30.tiny_bound = 0x0010000000000000, /* Smallest normal. */31.thresh = 0x7fe0000000000000, /* asuint64 (infinity) - tiny_bound. */32};3334#define MantissaMask 0x000fffffffffffff35#define HalfExp 0x3fe00000000000003637static svfloat64_t NOINLINE38special_case (svfloat64_t x, svfloat64_t y, svbool_t special)39{40return sv_call_f64 (cbrt, x, y, special);41}4243static inline svfloat64_t44shifted_lookup (const svbool_t pg, const float64_t *table, svint64_t i)45{46return svld1_gather_index (pg, table, svadd_x (pg, i, 2));47}4849/* Approximation for double-precision vector cbrt(x), using low-order50polynomial and two Newton iterations.5152The vector version of frexp does not handle subnormals53correctly. As a result these need to be handled by the scalar54fallback, where accuracy may be worse than that of the vector code55path.5657Greatest observed error in the normal range is 1.79 ULP. Errors repeat58according to the exponent, for instance an error observed for double value m59* 2^e will be observed for any input m * 2^(e + 3*i), where i is an integer.60_ZGVsMxv_cbrt (0x0.3fffb8d4413f3p-1022) got 0x1.965f53b0e5d97p-34261want 0x1.965f53b0e5d95p-342. */62svfloat64_t SV_NAME_D1 (cbrt) (svfloat64_t x, const svbool_t pg)63{64const struct data *d = ptr_barrier (&data);6566svfloat64_t ax = svabs_x (pg, x);67svuint64_t iax = svreinterpret_u64 (ax);68svuint64_t sign = sveor_x (pg, svreinterpret_u64 (x), iax);6970/* Subnormal, +/-0 and special values. */71svbool_t special = svcmpge (pg, svsub_x (pg, iax, d->tiny_bound), d->thresh);7273/* Decompose |x| into m * 2^e, where m is in [0.5, 1.0]. This is a vector74version of frexp, which gets subnormal values wrong - these have to be75special-cased as a result. */76svfloat64_t m = svreinterpret_f64 (svorr_x (77pg, svand_x (pg, svreinterpret_u64 (x), MantissaMask), HalfExp));78svint64_t e79= svsub_x (pg, svreinterpret_s64 (svlsr_x (pg, iax, 52)), d->exp_bias);8081/* Calculate rough approximation for cbrt(m) in [0.5, 1.0], starting point82for Newton iterations. */83svfloat64_t p84= sv_pairwise_poly_3_f64_x (pg, m, svmul_x (pg, m, m), d->poly);8586/* Two iterations of Newton's method for iteratively approximating cbrt. */87svfloat64_t m_by_3 = svmul_x (pg, m, d->one_third);88svfloat64_t a = svmla_x (pg, svdiv_x (pg, m_by_3, svmul_x (pg, p, p)), p,89d->two_thirds);90a = svmla_x (pg, svdiv_x (pg, m_by_3, svmul_x (pg, a, a)), a, d->two_thirds);9192/* Assemble the result by the following:9394cbrt(x) = cbrt(m) * 2 ^ (e / 3).9596We can get 2 ^ round(e / 3) using ldexp and integer divide, but since e is97not necessarily a multiple of 3 we lose some information.9899Let q = 2 ^ round(e / 3), then t = 2 ^ (e / 3) / q.100101Then we know t = 2 ^ (i / 3), where i is the remainder from e / 3, which102is an integer in [-2, 2], and can be looked up in the table T. Hence the103result is assembled as:104105cbrt(x) = cbrt(m) * t * 2 ^ round(e / 3) * sign. */106svfloat64_t eb3f = svmul_x (pg, svcvt_f64_x (pg, e), d->one_third);107svint64_t ey = svcvt_s64_x (pg, eb3f);108svint64_t em3 = svmls_x (pg, e, ey, 3);109110svfloat64_t my = shifted_lookup (pg, d->table, em3);111my = svmul_x (pg, my, a);112113/* Vector version of ldexp. */114svfloat64_t y = svscale_x (pg, my, ey);115116if (unlikely (svptest_any (pg, special)))117return special_case (118x, svreinterpret_f64 (svorr_x (pg, svreinterpret_u64 (y), sign)),119special);120121/* Copy sign. */122return svreinterpret_f64 (svorr_x (pg, svreinterpret_u64 (y), sign));123}124125/* Worse-case ULP error assumes that scalar fallback is GLIBC 2.40 cbrt, which126has ULP error of 3.67 at 0x1.7a337e1ba1ec2p-257 [1]. Largest observed error127in the vector path is 1.79 ULP.128[1] Innocente, V., & Zimmermann, P. (2024). Accuracy of Mathematical129Functions in Single, Double, Double Extended, and Quadruple Precision. */130TEST_SIG (SV, D, 1, cbrt, -10.0, 10.0)131TEST_ULP (SV_NAME_D1 (cbrt), 3.17)132TEST_DISABLE_FENV (SV_NAME_D1 (cbrt))133TEST_SYM_INTERVAL (SV_NAME_D1 (cbrt), 0, inf, 1000000)134CLOSE_SVE_ATTR135136137