Path: blob/main/contrib/arm-optimized-routines/math/aarch64/experimental/cosh_2u.c
48378 views
/*1* Double-precision cosh(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 "test_sig.h"9#include "test_defs.h"10#include "exp_inline.h"1112#define AbsMask 0x7fffffffffffffff13#define SpecialBound \140x40861da04cbafe44 /* 0x1.61da04cbafe44p+9, above which exp overflows. */1516static double17specialcase (double x, uint64_t iax)18{19if (iax == 0x7ff0000000000000)20return INFINITY;21if (iax > 0x7ff0000000000000)22return __math_invalid (x);23/* exp overflows above SpecialBound. At this magnitude cosh(x) is dominated24by exp(x), so we can approximate cosh(x) by (exp(|x|/2)) ^ 2 / 2. */25double t = exp_inline (asdouble (iax) / 2, 0);26return (0.5 * t) * t;27}2829/* Approximation for double-precision cosh(x).30cosh(x) = (exp(x) + exp(-x)) / 2.31The greatest observed error is in the special region, 1.93 ULP:32cosh(0x1.628af341989dap+9) got 0x1.fdf28623ef921p+102133want 0x1.fdf28623ef923p+1021.3435The greatest observed error in the non-special region is 1.03 ULP:36cosh(0x1.502cd8e56ab3bp+0) got 0x1.fe54962842d0ep+037want 0x1.fe54962842d0fp+0. */38double39cosh (double x)40{41uint64_t ix = asuint64 (x);42uint64_t iax = ix & AbsMask;4344/* exp overflows a little bit before cosh, so use special-case handler for45the gap, as well as special values. */46if (unlikely (iax >= SpecialBound))47return specialcase (x, iax);4849double ax = asdouble (iax);50/* Use double-precision exp helper to calculate exp(x), then:51cosh(x) = exp(|x|) / 2 + 1 / (exp(|x| * 2). */52double t = exp_inline (ax, 0);53return 0.5 * t + 0.5 / t;54}5556TEST_SIG (S, D, 1, cosh, -10.0, 10.0)57TEST_ULP (cosh, 1.43)58TEST_SYM_INTERVAL (cosh, 0, 0x1.61da04cbafe44p+9, 100000)59TEST_SYM_INTERVAL (cosh, 0x1.61da04cbafe44p+9, 0x1p10, 1000)60TEST_SYM_INTERVAL (cosh, 0x1p10, inf, 100)616263