asinhf.c
1 /* 2 * Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without modification, 5 * are permitted provided that the following conditions are met: 6 * 1. Redistributions of source code must retain the above copyright notice, 7 * this list of conditions and the following disclaimer. 8 * 2. Redistributions in binary form must reproduce the above copyright notice, 9 * this list of conditions and the following disclaimer in the documentation 10 * and/or other materials provided with the distribution. 11 * 3. Neither the name of the copyright holder nor the names of its contributors 12 * may be used to endorse or promote products derived from this software without 13 * specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 21 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 * POSSIBILITY OF SUCH DAMAGE. 25 * 26 */ 27 28 #include "libm_amd.h" 29 #include "libm_util_amd.h" 30 #include "libm_special.h" 31 32 #undef _FUNCNAME 33 #define _FUNCNAME "asinhf" 34 float FN_PROTOTYPE_REF(asinhf)(float x) 35 { 36 37 double dx; 38 unsigned int ux, ax, xneg; 39 double absx, r, rarg, t, poly; 40 41 static const unsigned int 42 rteps = 0x39800000, /* sqrt(eps) = 2.44140625000000000000e-04 */ 43 recrteps = 0x46000000; /* 1/rteps = 4.09600000000000000000e+03 */ 44 45 static const double 46 log2 = 6.93147180559945286227e-01; /* 0x3fe62e42fefa39ef */ 47 48 GET_BITS_SP32(x, ux); 49 ax = ux & ~SIGNBIT_SP32; 50 xneg = ux & SIGNBIT_SP32; 51 52 if ((ux & EXPBITS_SP32) == EXPBITS_SP32) 53 { 54 /* x is either NaN or infinity */ 55 if (ux & MANTBITS_SP32) 56 { 57 /* x is NaN */ 58 #ifdef WINDOWS 59 return __amd_handle_errorf(_FUNCNAME,__amd_asinh, ux|0x00400000, _DOMAIN, AMD_F_NONE, EDOM, x, 0.0F,1); 60 #else 61 if (ux & QNAN_MASK_32) 62 return __amd_handle_errorf(_FUNCNAME,__amd_asinh, ux|0x00400000, _DOMAIN, AMD_F_NONE, EDOM, x, 0.0F,1); 63 else 64 return __amd_handle_errorf(_FUNCNAME,__amd_asinh, ux|0x00400000, _DOMAIN, AMD_F_INVALID, EDOM, x, 0.0F,1); 65 #endif 66 } 67 else 68 { 69 /* x is infinity. Return the same infinity. */ 70 return x; 71 } 72 } 73 else if (ax < rteps) /* abs(x) < sqrt(epsilon) */ 74 { 75 if (ax == 0x00000000) 76 { 77 /* x is +/-zero. Return the same zero. */ 78 return x; 79 } 80 else 81 { 82 /* Tiny arguments approximated by asinhf(x) = x 83 - avoid slow operations on denormalized numbers */ 84 #ifdef WINDOWS 85 return x; //return valf_with_flags(x,AMD_F_INEXACT); 86 #else 87 return __amd_handle_errorf(_FUNCNAME,__amd_asinh, ux, _UNDERFLOW, AMD_F_UNDERFLOW|AMD_F_INEXACT, ERANGE, x, 0.0F,1); 88 #endif 89 } 90 } 91 92 dx = x; 93 if (xneg) 94 absx = -dx; 95 else 96 absx = dx; 97 98 if (ax <= 0x40800000) /* abs(x) <= 4.0 */ 99 { 100 /* Arguments less than 4.0 in magnitude are 101 approximated by [4,4] minimax polynomials 102 */ 103 t = dx*dx; 104 if (ax <= 0x40000000) /* abs(x) <= 2 */ 105 poly = 106 (-0.1152965835871758072e-1 + 107 (-0.1480204186473758321e-1 + 108 (-0.5063201055468483248e-2 + 109 (-0.4162727710583425360e-3 - 110 0.1177198915954942694e-5 * t) * t) * t) * t) / 111 (0.6917795026025976739e-1 + 112 (0.1199423176003939087e+0 + 113 (0.6582362487198468066e-1 + 114 (0.1260024978680227945e-1 + 115 0.6284381367285534560e-3 * t) * t) * t) * t); 116 else 117 poly = 118 (-0.185462290695578589e-2 + 119 (-0.113672533502734019e-2 + 120 (-0.142208387300570402e-3 + 121 (-0.339546014993079977e-5 - 122 0.151054665394480990e-8 * t) * t) * t) * t) / 123 (0.111486158580024771e-1 + 124 (0.117782437980439561e-1 + 125 (0.325903773532674833e-2 + 126 (0.255902049924065424e-3 + 127 0.434150786948890837e-5 * t) * t) * t) * t); 128 return (float)(dx + dx*t*poly); 129 } 130 else 131 { 132 /* abs(x) > 4.0 */ 133 if (ax > recrteps) 134 { 135 /* Arguments greater than 1/sqrt(epsilon) in magnitude are 136 approximated by asinhf(x) = ln(2) + ln(abs(x)), with sign of x */ 137 r = FN_PROTOTYPE(log)(absx) + log2; 138 } 139 else 140 { 141 rarg = absx*absx+1.0; 142 /* Arguments such that 4.0 <= abs(x) <= 1/sqrt(epsilon) are 143 approximated by 144 asinhf(x) = ln(abs(x) + sqrt(x*x+1)) 145 with the sign of x (see Abramowitz and Stegun 4.6.20) */ 146 /* Use assembly instruction to compute r = sqrt(rarg); */ 147 ASMSQRT(rarg,r); 148 r += absx; 149 r = FN_PROTOTYPE(log)(r); 150 } 151 if (xneg) 152 return (float)(-r); 153 else 154 return (float)r; 155 } 156 } 157 158