Path: blob/main/contrib/arm-optimized-routines/math/aarch64/advsimd/cbrt.c
48378 views
/*1* Double-precision vector cbrt(x) function.2*3* Copyright (c) 2022-2024, Arm Limited.4* SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception5*/67#include "v_math.h"8#include "test_sig.h"9#include "test_defs.h"10#include "v_poly_f64.h"1112const static struct data13{14float64x2_t poly[4], one_third, shift;15int64x2_t exp_bias;16uint64x2_t abs_mask, tiny_bound;17uint32x4_t thresh;18double table[5];19} data = {20.shift = V2 (0x1.8p52),21.poly = { /* Generated with fpminimax in [0.5, 1]. */22V2 (0x1.c14e8ee44767p-2), V2 (0x1.dd2d3f99e4c0ep-1),23V2 (-0x1.08e83026b7e74p-1), V2 (0x1.2c74eaa3ba428p-3) },24.exp_bias = V2 (1022),25.abs_mask = V2(0x7fffffffffffffff),26.tiny_bound = V2(0x0010000000000000), /* Smallest normal. */27.thresh = V4(0x7fe00000), /* asuint64 (infinity) - tiny_bound. */28.one_third = V2(0x1.5555555555555p-2),29.table = { /* table[i] = 2^((i - 2) / 3). */300x1.428a2f98d728bp-1, 0x1.965fea53d6e3dp-1, 0x1p0,310x1.428a2f98d728bp0, 0x1.965fea53d6e3dp0 }32};3334#define MantissaMask v_u64 (0x000fffffffffffff)3536static float64x2_t NOINLINE VPCS_ATTR37special_case (float64x2_t x, float64x2_t y, uint32x2_t special)38{39return v_call_f64 (cbrt, x, y, vmovl_u32 (special));40}4142/* Approximation for double-precision vector cbrt(x), using low-order43polynomial and two Newton iterations.4445The vector version of frexp does not handle subnormals46correctly. As a result these need to be handled by the scalar47fallback, where accuracy may be worse than that of the vector code48path.4950Greatest observed error in the normal range is 1.79 ULP. Errors repeat51according to the exponent, for instance an error observed for double value52m * 2^e will be observed for any input m * 2^(e + 3*i), where i is an53integer.54_ZGVnN2v_cbrt (0x1.fffff403f0bc6p+1) got 0x1.965fe72821e9bp+055want 0x1.965fe72821e99p+0. */56VPCS_ATTR float64x2_t V_NAME_D1 (cbrt) (float64x2_t x)57{58const struct data *d = ptr_barrier (&data);59uint64x2_t iax = vreinterpretq_u64_f64 (vabsq_f64 (x));6061/* Subnormal, +/-0 and special values. */62uint32x2_t special63= vcge_u32 (vsubhn_u64 (iax, d->tiny_bound), vget_low_u32 (d->thresh));6465/* Decompose |x| into m * 2^e, where m is in [0.5, 1.0]. This is a vector66version of frexp, which gets subnormal values wrong - these have to be67special-cased as a result. */68float64x2_t m = vbslq_f64 (MantissaMask, x, v_f64 (0.5));69int64x2_t exp_bias = d->exp_bias;70uint64x2_t ia12 = vshrq_n_u64 (iax, 52);71int64x2_t e = vsubq_s64 (vreinterpretq_s64_u64 (ia12), exp_bias);7273/* Calculate rough approximation for cbrt(m) in [0.5, 1.0], starting point74for Newton iterations. */75float64x2_t p = v_pairwise_poly_3_f64 (m, vmulq_f64 (m, m), d->poly);76float64x2_t one_third = d->one_third;77/* Two iterations of Newton's method for iteratively approximating cbrt. */78float64x2_t m_by_3 = vmulq_f64 (m, one_third);79float64x2_t two_thirds = vaddq_f64 (one_third, one_third);80float64x2_t a81= vfmaq_f64 (vdivq_f64 (m_by_3, vmulq_f64 (p, p)), two_thirds, p);82a = vfmaq_f64 (vdivq_f64 (m_by_3, vmulq_f64 (a, a)), two_thirds, a);8384/* Assemble the result by the following:8586cbrt(x) = cbrt(m) * 2 ^ (e / 3).8788We can get 2 ^ round(e / 3) using ldexp and integer divide, but since e is89not necessarily a multiple of 3 we lose some information.9091Let q = 2 ^ round(e / 3), then t = 2 ^ (e / 3) / q.9293Then we know t = 2 ^ (i / 3), where i is the remainder from e / 3, which94is an integer in [-2, 2], and can be looked up in the table T. Hence the95result is assembled as:9697cbrt(x) = cbrt(m) * t * 2 ^ round(e / 3) * sign. */9899float64x2_t ef = vcvtq_f64_s64 (e);100float64x2_t eb3f = vrndnq_f64 (vmulq_f64 (ef, one_third));101int64x2_t em3 = vcvtq_s64_f64 (vfmsq_f64 (ef, eb3f, v_f64 (3)));102int64x2_t ey = vcvtq_s64_f64 (eb3f);103104float64x2_t my = (float64x2_t){ d->table[em3[0] + 2], d->table[em3[1] + 2] };105my = vmulq_f64 (my, a);106107/* Vector version of ldexp. */108float64x2_t y = vreinterpretq_f64_s64 (109vshlq_n_s64 (vaddq_s64 (ey, vaddq_s64 (exp_bias, v_s64 (1))), 52));110y = vmulq_f64 (y, my);111112if (unlikely (v_any_u32h (special)))113return special_case (x, vbslq_f64 (d->abs_mask, y, x), special);114115/* Copy sign. */116return vbslq_f64 (d->abs_mask, y, x);117}118119/* Worse-case ULP error assumes that scalar fallback is GLIBC 2.40 cbrt, which120has ULP error of 3.67 at 0x1.7a337e1ba1ec2p-257 [1]. Largest observed error121in the vector path is 1.79 ULP.122[1] Innocente, V., & Zimmermann, P. (2024). Accuracy of Mathematical123Functions in Single, Double, Double Extended, and Quadruple Precision. */124TEST_ULP (V_NAME_D1 (cbrt), 3.17)125TEST_SIG (V, D, 1, cbrt, -10.0, 10.0)126TEST_SYM_INTERVAL (V_NAME_D1 (cbrt), 0, inf, 1000000)127128129