146b15fd1STue Ly //===-- Single-precision asinh function -----------------------------------===// 246b15fd1STue Ly // 346b15fd1STue Ly // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 446b15fd1STue Ly // See https://llvm.org/LICENSE.txt for license information. 546b15fd1STue Ly // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 646b15fd1STue Ly // 746b15fd1STue Ly //===----------------------------------------------------------------------===// 846b15fd1STue Ly 946b15fd1STue Ly #include "src/math/asinhf.h" 1046b15fd1STue Ly #include "src/__support/FPUtil/FPBits.h" 1146b15fd1STue Ly #include "src/__support/FPUtil/PolyEval.h" 1246b15fd1STue Ly #include "src/__support/FPUtil/multiply_add.h" 1346b15fd1STue Ly #include "src/__support/FPUtil/sqrt.h" 14*5ff3ff33SPetr Hosek #include "src/__support/macros/config.h" 15737e1cd1SGuillaume Chatelet #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY 1646b15fd1STue Ly #include "src/math/generic/common_constants.h" 1746b15fd1STue Ly #include "src/math/generic/explogxf.h" 1846b15fd1STue Ly 19*5ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL { 2046b15fd1STue Ly 2146b15fd1STue Ly LLVM_LIBC_FUNCTION(float, asinhf, (float x)) { 22a9af317fSGuillaume Chatelet using FPBits_t = typename fputil::FPBits<float>; 23a9af317fSGuillaume Chatelet FPBits_t xbits(x); 2446b15fd1STue Ly uint32_t x_u = xbits.uintval(); 25ea43c8eeSGuillaume Chatelet uint32_t x_abs = xbits.abs().uintval(); 2646b15fd1STue Ly 2746b15fd1STue Ly // |x| <= 2^-3 2829f8e076SGuillaume Chatelet if (LIBC_UNLIKELY(x_abs <= 0x3e80'0000U)) { 2946b15fd1STue Ly // |x| <= 2^-26 3029f8e076SGuillaume Chatelet if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) { 317d11a592SAlex Brachet return static_cast<float>(LIBC_UNLIKELY(x_abs == 0) 327d11a592SAlex Brachet ? x 337d11a592SAlex Brachet : (x - 0x1.5555555555555p-3 * x * x * x)); 3446b15fd1STue Ly } 3546b15fd1STue Ly 3646b15fd1STue Ly double x_d = x; 3746b15fd1STue Ly double x_sq = x_d * x_d; 3846b15fd1STue Ly // Generated by Sollya with: 3946b15fd1STue Ly // > P = fpminimax(asinh(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14, 16], [|D...|], 4046b15fd1STue Ly // [0, 2^-2]); 4146b15fd1STue Ly double p = fputil::polyeval( 4246b15fd1STue Ly x_sq, 0.0, -0x1.555555555551ep-3, 0x1.3333333325495p-4, 4346b15fd1STue Ly -0x1.6db6db5a7622bp-5, 0x1.f1c70f82928c6p-6, -0x1.6e893934266b7p-6, 4446b15fd1STue Ly 0x1.1c0b41d3fbe78p-6, -0x1.c0f47810b3c4fp-7, 0x1.2c8602690143dp-7); 457d11a592SAlex Brachet return static_cast<float>(fputil::multiply_add(x_d, p, x_d)); 4646b15fd1STue Ly } 4746b15fd1STue Ly 4846b15fd1STue Ly const double SIGN[2] = {1.0, -1.0}; 4946b15fd1STue Ly double x_sign = SIGN[x_u >> 31]; 5046b15fd1STue Ly double x_d = x; 5146b15fd1STue Ly 5246b15fd1STue Ly // Helper functions to set results for exceptional cases. 5346b15fd1STue Ly auto round_result_slightly_down = [x_sign](float r) -> float { 5446b15fd1STue Ly return fputil::multiply_add(static_cast<float>(x_sign), r, 5546b15fd1STue Ly static_cast<float>(x_sign) * (-0x1.0p-24f)); 5646b15fd1STue Ly }; 5746b15fd1STue Ly auto round_result_slightly_up = [x_sign](float r) -> float { 5846b15fd1STue Ly return fputil::multiply_add(static_cast<float>(x_sign), r, 5946b15fd1STue Ly static_cast<float>(x_sign) * 0x1.0p-24f); 6046b15fd1STue Ly }; 6146b15fd1STue Ly 6229f8e076SGuillaume Chatelet if (LIBC_UNLIKELY(x_abs >= 0x4bdd'65a5U)) { 63f506192cSGuillaume Chatelet if (LIBC_UNLIKELY(xbits.is_inf_or_nan())) 6446b15fd1STue Ly return x; 6546b15fd1STue Ly 6646b15fd1STue Ly // Exceptional cases when x > 2^24. 6746b15fd1STue Ly switch (x_abs) { 6846b15fd1STue Ly case 0x4bdd65a5: // |x| = 0x1.bacb4ap24f 6946b15fd1STue Ly return round_result_slightly_down(0x1.1e0696p4f); 7046b15fd1STue Ly case 0x4c803f2c: // |x| = 0x1.007e58p26f 7146b15fd1STue Ly return round_result_slightly_down(0x1.2b786cp4f); 7246b15fd1STue Ly case 0x4f8ffb03: // |x| = 0x1.1ff606p32f 7346b15fd1STue Ly return round_result_slightly_up(0x1.6fdd34p4f); 7446b15fd1STue Ly case 0x5c569e88: // |x| = 0x1.ad3d1p57f 7546b15fd1STue Ly return round_result_slightly_up(0x1.45c146p5f); 7646b15fd1STue Ly case 0x5e68984e: // |x| = 0x1.d1309cp61f 7746b15fd1STue Ly return round_result_slightly_up(0x1.5c9442p5f); 7846b15fd1STue Ly case 0x655890d3: // |x| = 0x1.b121a6p75f 7946b15fd1STue Ly return round_result_slightly_down(0x1.a9a3f2p5f); 8046b15fd1STue Ly case 0x65de7ca6: // |x| = 0x1.bcf94cp76f 8146b15fd1STue Ly return round_result_slightly_up(0x1.af66cp5f); 8246b15fd1STue Ly case 0x6eb1a8ec: // |x| = 0x1.6351d8p94f 8346b15fd1STue Ly return round_result_slightly_down(0x1.08b512p6f); 8446b15fd1STue Ly case 0x7997f30a: // |x| = 0x1.2fe614p116f 8546b15fd1STue Ly return round_result_slightly_up(0x1.451436p6f); 8646b15fd1STue Ly } 8746b15fd1STue Ly } else { 8846b15fd1STue Ly // Exceptional cases when x < 2^24. 8929f8e076SGuillaume Chatelet if (LIBC_UNLIKELY(x_abs == 0x45abaf26)) { 9046b15fd1STue Ly // |x| = 0x1.575e4cp12f 9146b15fd1STue Ly return round_result_slightly_down(0x1.29becap3f); 9246b15fd1STue Ly } 9329f8e076SGuillaume Chatelet if (LIBC_UNLIKELY(x_abs == 0x49d29048)) { 9446b15fd1STue Ly // |x| = 0x1.a5209p20f 9546b15fd1STue Ly return round_result_slightly_down(0x1.e1b92p3f); 9646b15fd1STue Ly } 9746b15fd1STue Ly } 9846b15fd1STue Ly 9946b15fd1STue Ly // asinh(x) = log(x + sqrt(x^2 + 1)) 1007d11a592SAlex Brachet return static_cast<float>( 101a2393435SOverMighty x_sign * log_eval(fputil::multiply_add( 102a2393435SOverMighty x_d, x_sign, 103a2393435SOverMighty fputil::sqrt<double>(fputil::multiply_add(x_d, x_d, 1.0))))); 10446b15fd1STue Ly } 10546b15fd1STue Ly 106*5ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL 107