Path: blob/main/contrib/arm-optimized-routines/math/aarch64/experimental/atanh_3u.c
48378 views
/*1* Double-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 "poly_scalar_f64.h"9#include "test_sig.h"10#include "test_defs.h"1112#define AbsMask 0x7fffffffffffffff13#define Half 0x3fe000000000000014#define One 0x3ff000000000000015#define Ln2Hi 0x1.62e42fefa3800p-116#define Ln2Lo 0x1.ef35793c76730p-4517#define OneMHfRt2Top \180x00095f62 /* top32(asuint64(1)) - top32(asuint64(sqrt(2)/2)). */19#define OneTop12 0x3ff20#define HfRt2Top 0x3fe6a09e /* top32(asuint64(sqrt(2)/2)). */21#define BottomMask 0xffffffff2223static inline double24log1p_inline (double x)25{26/* Helper for calculating log(1 + x) using order-18 polynomial on a reduced27interval. Copied from log1p_2u.c, with no special-case handling. See that28file for details of the algorithm. */29double m = x + 1;30uint64_t mi = asuint64 (m);3132/* Decompose x + 1 into (f + 1) * 2^k, with k chosen such that f is in33[sqrt(2)/2, sqrt(2)]. */34uint32_t u = (mi >> 32) + OneMHfRt2Top;35int32_t k = (int32_t) (u >> 20) - OneTop12;36uint32_t utop = (u & 0x000fffff) + HfRt2Top;37uint64_t u_red = ((uint64_t) utop << 32) | (mi & BottomMask);38double f = asdouble (u_red) - 1;3940/* Correction term for round-off in f. */41double cm = (x - (m - 1)) / m;4243/* Approximate log1p(f) with polynomial. */44double f2 = f * f;45double f4 = f2 * f2;46double f8 = f4 * f4;47double p = fma (48f, estrin_18_f64 (f, f2, f4, f8, f8 * f8, __log1p_data.coeffs) * f, f);4950/* Recombine log1p(x) = k*log2 + log1p(f) + c/m. */51double kd = k;52double y = fma (Ln2Lo, kd, cm);53return y + fma (Ln2Hi, kd, p);54}5556/* Approximation for double-precision inverse tanh(x), using a simplified57version of log1p. Greatest observed error is 3.00 ULP:58atanh(0x1.e58f3c108d714p-4) got 0x1.e7da77672a647p-459want 0x1.e7da77672a64ap-4. */60double61atanh (double x)62{63uint64_t ix = asuint64 (x);64uint64_t sign = ix & ~AbsMask;65uint64_t ia = ix & AbsMask;6667if (unlikely (ia == One))68return __math_divzero (sign >> 32);6970if (unlikely (ia > One))71return __math_invalid (x);7273double halfsign = asdouble (Half | sign);74double ax = asdouble (ia);75return halfsign * log1p_inline ((2 * ax) / (1 - ax));76}7778TEST_SIG (S, D, 1, atanh, -1.0, 1.0)79TEST_ULP (atanh, 3.00)80TEST_SYM_INTERVAL (atanh, 0, 0x1p-23, 10000)81TEST_SYM_INTERVAL (atanh, 0x1p-23, 1, 90000)82TEST_SYM_INTERVAL (atanh, 1, inf, 100)838485