blob: 3dae149a4a643f8007e39e60d411250be617fa68 [file] [edit]
//===-- Implementation of tanbf16 function --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_TANBF16_H
#define LLVM_LIBC_SRC___SUPPORT_MATH_TANBF16_H
#include "hdr/errno_macros.h"
#include "hdr/fenv_macros.h"
#include "sincosf_utils.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/bfloat16.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/multiply_add.h"
#include "src/__support/macros/optimization.h"
namespace LIBC_NAMESPACE_DECL {
namespace math {
LIBC_INLINE bfloat16 tanbf16(bfloat16 x) {
using FPBits = fputil::FPBits<bfloat16>;
FPBits xbits(x);
uint16_t x_u = xbits.uintval();
uint16_t x_abs = x_u & 0x7fff;
float xf = x;
// NaN or -/+ INF
if (x_abs >= 0x7F80) {
// NaN
if (xbits.is_nan()) {
if (xbits.is_signaling_nan()) {
fputil::raise_except_if_required(FE_INVALID);
return FPBits::quiet_nan().get_val();
}
return x;
}
//|x| is +/- INF
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
return x + FPBits::quiet_nan().get_val();
}
// Through Exhaustive testing -
// The last value where tan(x) ~ x is 0x3db8
if (LIBC_UNLIKELY(x_abs <= 0x3db8)) {
// |x| = {0}
if (LIBC_UNLIKELY(x_abs == 0)) {
return x;
}
return fputil::cast<bfloat16>(fputil::multiply_add(xf, 0x1.0p-11f, xf));
}
double xd = static_cast<double>(xf);
uint32_t x_abs_f = fputil::FPBits<float>(xf).uintval() & 0x7fffffff;
double sin_k, cos_k, sin_y, cosm1_y;
// TODO: Use bfloat16 version for inv_trigf_utils_internals after they are
// available
// Tracking issue :
// https://github.com/llvm/llvm-project/issues/202079
sincosf_utils_internal::sincosf_eval(xd, x_abs_f, sin_k, cos_k, sin_y,
cosm1_y);
return fputil::cast<bfloat16>(
fputil::multiply_add(sin_y, cos_k,
fputil::multiply_add(cosm1_y, sin_k, sin_k)) /
fputil::multiply_add(sin_y, -sin_k,
fputil::multiply_add(cosm1_y, cos_k, cos_k)));
}
} // namespace math
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_MATH_TANBF16_H