1*71db0c75SAndroid Build Coastguard Worker //===-- Half-precision cospif function ------------------------------------===// 2*71db0c75SAndroid Build Coastguard Worker // 3*71db0c75SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*71db0c75SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information. 5*71db0c75SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*71db0c75SAndroid Build Coastguard Worker // 7*71db0c75SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 8*71db0c75SAndroid Build Coastguard Worker 9*71db0c75SAndroid Build Coastguard Worker #include "src/math/cospif16.h" 10*71db0c75SAndroid Build Coastguard Worker #include "hdr/errno_macros.h" 11*71db0c75SAndroid Build Coastguard Worker #include "hdr/fenv_macros.h" 12*71db0c75SAndroid Build Coastguard Worker #include "sincosf16_utils.h" 13*71db0c75SAndroid Build Coastguard Worker #include "src/__support/FPUtil/FEnvImpl.h" 14*71db0c75SAndroid Build Coastguard Worker #include "src/__support/FPUtil/FPBits.h" 15*71db0c75SAndroid Build Coastguard Worker #include "src/__support/FPUtil/cast.h" 16*71db0c75SAndroid Build Coastguard Worker #include "src/__support/FPUtil/multiply_add.h" 17*71db0c75SAndroid Build Coastguard Worker #include "src/__support/macros/optimization.h" 18*71db0c75SAndroid Build Coastguard Worker 19*71db0c75SAndroid Build Coastguard Worker namespace LIBC_NAMESPACE_DECL { 20*71db0c75SAndroid Build Coastguard Worker 21*71db0c75SAndroid Build Coastguard Worker LLVM_LIBC_FUNCTION(float16, cospif16, (float16 x)) { 22*71db0c75SAndroid Build Coastguard Worker using FPBits = typename fputil::FPBits<float16>; 23*71db0c75SAndroid Build Coastguard Worker FPBits xbits(x); 24*71db0c75SAndroid Build Coastguard Worker 25*71db0c75SAndroid Build Coastguard Worker uint16_t x_u = xbits.uintval(); 26*71db0c75SAndroid Build Coastguard Worker uint16_t x_abs = x_u & 0x7fff; 27*71db0c75SAndroid Build Coastguard Worker float xf = x; 28*71db0c75SAndroid Build Coastguard Worker 29*71db0c75SAndroid Build Coastguard Worker // Range reduction: 30*71db0c75SAndroid Build Coastguard Worker // For |x| > 1/32, we perform range reduction as follows: 31*71db0c75SAndroid Build Coastguard Worker // Find k and y such that: 32*71db0c75SAndroid Build Coastguard Worker // x = (k + y) * 1/32 33*71db0c75SAndroid Build Coastguard Worker // k is an integer 34*71db0c75SAndroid Build Coastguard Worker // |y| < 0.5 35*71db0c75SAndroid Build Coastguard Worker // 36*71db0c75SAndroid Build Coastguard Worker // This is done by performing: 37*71db0c75SAndroid Build Coastguard Worker // k = round(x * 32) 38*71db0c75SAndroid Build Coastguard Worker // y = x * 32 - k 39*71db0c75SAndroid Build Coastguard Worker // 40*71db0c75SAndroid Build Coastguard Worker // Once k and y are computed, we then deduce the answer by the cosine of sum 41*71db0c75SAndroid Build Coastguard Worker // formula: 42*71db0c75SAndroid Build Coastguard Worker // cos(x * pi) = cos((k + y) * pi/32) 43*71db0c75SAndroid Build Coastguard Worker // = cos(k * pi/32) * cos(y * pi/32) + 44*71db0c75SAndroid Build Coastguard Worker // sin(y * pi/32) * sin(k * pi/32) 45*71db0c75SAndroid Build Coastguard Worker 46*71db0c75SAndroid Build Coastguard Worker // For signed zeros 47*71db0c75SAndroid Build Coastguard Worker if (LIBC_UNLIKELY(x_abs == 0U)) 48*71db0c75SAndroid Build Coastguard Worker return fputil::cast<float16>(1.0f); 49*71db0c75SAndroid Build Coastguard Worker 50*71db0c75SAndroid Build Coastguard Worker // Numbers greater or equal to 2^10 are integers, or infinity, or NaN 51*71db0c75SAndroid Build Coastguard Worker if (LIBC_UNLIKELY(x_abs >= 0x6400)) { 52*71db0c75SAndroid Build Coastguard Worker if (LIBC_UNLIKELY(x_abs <= 0x67FF)) 53*71db0c75SAndroid Build Coastguard Worker return fputil::cast<float16>((x_abs & 0x1) ? -1.0f : 1.0f); 54*71db0c75SAndroid Build Coastguard Worker 55*71db0c75SAndroid Build Coastguard Worker // Check for NaN or infintiy values 56*71db0c75SAndroid Build Coastguard Worker if (LIBC_UNLIKELY(x_abs >= 0x7c00)) { 57*71db0c75SAndroid Build Coastguard Worker // If value is equal to infinity 58*71db0c75SAndroid Build Coastguard Worker if (x_abs == 0x7c00) { 59*71db0c75SAndroid Build Coastguard Worker fputil::set_errno_if_required(EDOM); 60*71db0c75SAndroid Build Coastguard Worker fputil::raise_except_if_required(FE_INVALID); 61*71db0c75SAndroid Build Coastguard Worker } 62*71db0c75SAndroid Build Coastguard Worker 63*71db0c75SAndroid Build Coastguard Worker return x + FPBits::quiet_nan().get_val(); 64*71db0c75SAndroid Build Coastguard Worker } 65*71db0c75SAndroid Build Coastguard Worker 66*71db0c75SAndroid Build Coastguard Worker return fputil::cast<float16>(1.0f); 67*71db0c75SAndroid Build Coastguard Worker } 68*71db0c75SAndroid Build Coastguard Worker 69*71db0c75SAndroid Build Coastguard Worker float sin_k, cos_k, sin_y, cosm1_y; 70*71db0c75SAndroid Build Coastguard Worker sincospif16_eval(xf, sin_k, cos_k, sin_y, cosm1_y); 71*71db0c75SAndroid Build Coastguard Worker 72*71db0c75SAndroid Build Coastguard Worker if (LIBC_UNLIKELY(sin_y == 0 && cos_k == 0)) 73*71db0c75SAndroid Build Coastguard Worker return fputil::cast<float16>(0.0f); 74*71db0c75SAndroid Build Coastguard Worker 75*71db0c75SAndroid Build Coastguard Worker // Since, cosm1_y = cos_y - 1, therefore: 76*71db0c75SAndroid Build Coastguard Worker // cos(x * pi) = cos_k(cosm1_y) + cos_k - sin_k * sin_y 77*71db0c75SAndroid Build Coastguard Worker return fputil::cast<float16>(fputil::multiply_add( 78*71db0c75SAndroid Build Coastguard Worker cos_k, cosm1_y, fputil::multiply_add(-sin_k, sin_y, cos_k))); 79*71db0c75SAndroid Build Coastguard Worker } 80*71db0c75SAndroid Build Coastguard Worker 81*71db0c75SAndroid Build Coastguard Worker } // namespace LIBC_NAMESPACE_DECL 82