Path: blob/main/contrib/arm-optimized-routines/math/aarch64/experimental/atanhf_3u1.c
48375 views
/*1* Single-precision atanh(x) function.2*3* Copyright (c) 2022-2024, Arm Limited.4* SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception5*/67#include "math_config.h"8#include "mathlib.h"9#include "test_sig.h"10#include "test_defs.h"1112#define AbsMask 0x7fffffff13#define Half 0x3f00000014#define One 0x3f80000015#define Four 0x4080000016#define Ln2 0x1.62e43p-1f17/* asuint(0x1p-12), below which atanhf(x) rounds to x. */18#define TinyBound 0x398000001920#define C(i) __log1pf_data.coeffs[i]2122static inline float23eval_poly (float m)24{25/* Approximate log(1+m) on [-0.25, 0.5] using Estrin scheme. */26float p_12 = fmaf (m, C (1), C (0));27float p_34 = fmaf (m, C (3), C (2));28float p_56 = fmaf (m, C (5), C (4));29float p_78 = fmaf (m, C (7), C (6));3031float m2 = m * m;32float p_02 = fmaf (m2, p_12, m);33float p_36 = fmaf (m2, p_56, p_34);34float p_79 = fmaf (m2, C (8), p_78);3536float m4 = m2 * m2;37float p_06 = fmaf (m4, p_36, p_02);3839return fmaf (m4 * p_79, m4, p_06);40}4142static inline float43log1pf_inline (float x)44{45/* Helper for calculating log(x + 1). Copied from log1pf_2u1.c, with no46special-case handling. See that file for details of the algorithm. */47float m = x + 1.0f;48int k = (asuint (m) - 0x3f400000) & 0xff800000;49float s = asfloat (Four - k);50float m_scale = asfloat (asuint (x) - k) + fmaf (0.25f, s, -1.0f);51float p = eval_poly (m_scale);52float scale_back = (float) k * 0x1.0p-23f;53return fmaf (scale_back, Ln2, p);54}5556/* Approximation for single-precision inverse tanh(x), using a simplified57version of log1p. Maximum error is 3.08 ULP:58atanhf(0x1.ff0d5p-5) got 0x1.ffb768p-559want 0x1.ffb76ep-5. */60float61atanhf (float x)62{63uint32_t ix = asuint (x);64uint32_t iax = ix & AbsMask;65uint32_t sign = ix & ~AbsMask;6667if (unlikely (iax < TinyBound))68return x;6970if (iax == One)71return __math_divzero (sign);7273if (unlikely (iax > One))74return __math_invalidf (x);7576float halfsign = asfloat (Half | sign);77float ax = asfloat (iax);78return halfsign * log1pf_inline ((2 * ax) / (1 - ax));79}8081TEST_SIG (S, F, 1, atanh, -1.0, 1.0)82TEST_ULP (atanhf, 2.59)83TEST_SYM_INTERVAL (atanhf, 0, 0x1p-12, 500)84TEST_SYM_INTERVAL (atanhf, 0x1p-12, 1, 200000)85TEST_SYM_INTERVAL (atanhf, 1, inf, 1000)868788