| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| //===-- Implementation header for exp2m1f16 ---------------------*- C++ -*-===// | ||
| // | ||
| // 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_MATH_EXP2M1F16_H | ||
| #define LLVM_LIBC_SRC_MATH_EXP2M1F16_H | ||
|
|
||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/properties/types.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| float16 exp2m1f16(float16 x); | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL | ||
|
|
||
| #endif // LLVM_LIBC_SRC_MATH_EXP2M1F16_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| //===-- Half-precision cosh(x) 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/coshf16.h" | ||
| #include "expxf16.h" | ||
| #include "hdr/errno_macros.h" | ||
| #include "hdr/fenv_macros.h" | ||
| #include "src/__support/FPUtil/FEnvImpl.h" | ||
| #include "src/__support/FPUtil/FPBits.h" | ||
| #include "src/__support/FPUtil/except_value_utils.h" | ||
| #include "src/__support/FPUtil/rounding_mode.h" | ||
| #include "src/__support/common.h" | ||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/optimization.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| static constexpr fputil::ExceptValues<float16, 9> COSHF16_EXCEPTS_POS = {{ | ||
| // x = 0x1.6ap-5, coshf16(x) = 0x1p+0 (RZ) | ||
| {0x29a8U, 0x3c00U, 1U, 0U, 1U}, | ||
| // x = 0x1.8c4p+0, coshf16(x) = 0x1.3a8p+1 (RZ) | ||
| {0x3e31U, 0x40eaU, 1U, 0U, 0U}, | ||
| // x = 0x1.994p+0, coshf16(x) = 0x1.498p+1 (RZ) | ||
| {0x3e65U, 0x4126U, 1U, 0U, 0U}, | ||
| // x = 0x1.b6p+0, coshf16(x) = 0x1.6d8p+1 (RZ) | ||
| {0x3ed8U, 0x41b6U, 1U, 0U, 1U}, | ||
| // x = 0x1.aap+1, coshf16(x) = 0x1.be8p+3 (RZ) | ||
| {0x42a8U, 0x4afaU, 1U, 0U, 1U}, | ||
| // x = 0x1.cc4p+1, coshf16(x) = 0x1.23cp+4 (RZ) | ||
| {0x4331U, 0x4c8fU, 1U, 0U, 0U}, | ||
| // x = 0x1.288p+2, coshf16(x) = 0x1.9b4p+5 (RZ) | ||
| {0x44a2U, 0x526dU, 1U, 0U, 0U}, | ||
| // x = 0x1.958p+2, coshf16(x) = 0x1.1a4p+8 (RZ) | ||
| {0x4656U, 0x5c69U, 1U, 0U, 0U}, | ||
| // x = 0x1.5fp+3, coshf16(x) = 0x1.c54p+14 (RZ) | ||
| {0x497cU, 0x7715U, 1U, 0U, 1U}, | ||
| }}; | ||
|
|
||
| static constexpr fputil::ExceptValues<float16, 4> COSHF16_EXCEPTS_NEG = {{ | ||
| // x = -0x1.6ap-5, coshf16(x) = 0x1p+0 (RZ) | ||
| {0xa9a8U, 0x3c00U, 1U, 0U, 1U}, | ||
| // x = -0x1.b6p+0, coshf16(x) = 0x1.6d8p+1 (RZ) | ||
| {0xbed8U, 0x41b6U, 1U, 0U, 1U}, | ||
| // x = -0x1.288p+2, coshf16(x) = 0x1.9b4p+5 (RZ) | ||
| {0xc4a2U, 0x526dU, 1U, 0U, 0U}, | ||
| // x = -0x1.5fp+3, coshf16(x) = 0x1.c54p+14 (RZ) | ||
| {0xc97cU, 0x7715U, 1U, 0U, 1U}, | ||
| }}; | ||
|
|
||
| LLVM_LIBC_FUNCTION(float16, coshf16, (float16 x)) { | ||
| using FPBits = fputil::FPBits<float16>; | ||
| FPBits x_bits(x); | ||
|
|
||
| uint16_t x_u = x_bits.uintval(); | ||
| uint16_t x_abs = x_u & 0x7fffU; | ||
|
|
||
| // When |x| >= acosh(2^16), or x is NaN. | ||
| if (LIBC_UNLIKELY(x_abs >= 0x49e5U)) { | ||
| // cosh(NaN) = NaN | ||
| if (x_bits.is_nan()) { | ||
| if (x_bits.is_signaling_nan()) { | ||
| fputil::raise_except_if_required(FE_INVALID); | ||
| return FPBits::quiet_nan().get_val(); | ||
| } | ||
|
|
||
| return x; | ||
| } | ||
|
|
||
| // When |x| >= acosh(2^16). | ||
| if (x_abs >= 0x49e5U) { | ||
| // cosh(+/-inf) = +inf | ||
| if (x_bits.is_inf()) | ||
| return FPBits::inf().get_val(); | ||
|
|
||
| switch (fputil::quick_get_round()) { | ||
| case FE_TONEAREST: | ||
| case FE_UPWARD: | ||
| fputil::set_errno_if_required(ERANGE); | ||
| fputil::raise_except_if_required(FE_OVERFLOW | FE_INEXACT); | ||
| return FPBits::inf().get_val(); | ||
| default: | ||
| return FPBits::max_normal().get_val(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (x_bits.is_pos()) { | ||
| if (auto r = COSHF16_EXCEPTS_POS.lookup(x_u); LIBC_UNLIKELY(r.has_value())) | ||
| return r.value(); | ||
| } else { | ||
| if (auto r = COSHF16_EXCEPTS_NEG.lookup(x_u); LIBC_UNLIKELY(r.has_value())) | ||
| return r.value(); | ||
| } | ||
|
|
||
| return eval_sinh_or_cosh</*IsSinh=*/false>(x); | ||
| } | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| //===-- Half-precision 10^x - 1 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/exp10m1f16.h" | ||
| #include "expxf16.h" | ||
| #include "hdr/errno_macros.h" | ||
| #include "hdr/fenv_macros.h" | ||
| #include "src/__support/FPUtil/FEnvImpl.h" | ||
| #include "src/__support/FPUtil/FPBits.h" | ||
| #include "src/__support/FPUtil/PolyEval.h" | ||
| #include "src/__support/FPUtil/except_value_utils.h" | ||
| #include "src/__support/FPUtil/multiply_add.h" | ||
| #include "src/__support/FPUtil/rounding_mode.h" | ||
| #include "src/__support/common.h" | ||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/optimization.h" | ||
| #include "src/__support/macros/properties/cpu_features.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| static constexpr fputil::ExceptValues<float16, 3> EXP10M1F16_EXCEPTS_LO = {{ | ||
| // (input, RZ output, RU offset, RD offset, RN offset) | ||
| // x = 0x1.5c4p-4, exp10m1f16(x) = 0x1.bacp-3 (RZ) | ||
| {0x2d71U, 0x32ebU, 1U, 0U, 0U}, | ||
| // x = -0x1.5ep-13, exp10m1f16(x) = -0x1.92cp-12 (RZ) | ||
| {0x8978U, 0x8e4bU, 0U, 1U, 0U}, | ||
| // x = -0x1.e2p-10, exp10m1f16(x) = -0x1.14cp-8 (RZ) | ||
| {0x9788U, 0x9c53U, 0U, 1U, 0U}, | ||
| }}; | ||
|
|
||
| #ifdef LIBC_TARGET_CPU_HAS_FMA | ||
| static constexpr size_t N_EXP10M1F16_EXCEPTS_HI = 3; | ||
| #else | ||
| static constexpr size_t N_EXP10M1F16_EXCEPTS_HI = 6; | ||
| #endif | ||
|
|
||
| static constexpr fputil::ExceptValues<float16, N_EXP10M1F16_EXCEPTS_HI> | ||
| EXP10M1F16_EXCEPTS_HI = {{ | ||
| // (input, RZ output, RU offset, RD offset, RN offset) | ||
| // x = 0x1.8f4p-2, exp10m1f16(x) = 0x1.744p+0 (RZ) | ||
| {0x363dU, 0x3dd1U, 1U, 0U, 0U}, | ||
| // x = 0x1.95cp-2, exp10m1f16(x) = 0x1.7d8p+0 (RZ) | ||
| {0x3657U, 0x3df6U, 1U, 0U, 0U}, | ||
| // x = 0x1.d04p-2, exp10m1f16(x) = 0x1.d7p+0 (RZ) | ||
| {0x3741U, 0x3f5cU, 1U, 0U, 1U}, | ||
| #ifndef LIBC_TARGET_CPU_HAS_FMA | ||
| // x = 0x1.0cp+1, exp10m1f16(x) = 0x1.ec4p+6 (RZ) | ||
| {0x4030U, 0x57b1U, 1U, 0U, 1U}, | ||
| // x = 0x1.1b8p+1, exp10m1f16(x) = 0x1.45cp+7 (RZ) | ||
| {0x406eU, 0x5917U, 1U, 0U, 1U}, | ||
| // x = 0x1.2f4p+2, exp10m1f16(x) = 0x1.ab8p+15 (RZ) | ||
| {0x44bdU, 0x7aaeU, 1U, 0U, 1U}, | ||
| #endif | ||
| }}; | ||
|
|
||
| LLVM_LIBC_FUNCTION(float16, exp10m1f16, (float16 x)) { | ||
| using FPBits = fputil::FPBits<float16>; | ||
| FPBits x_bits(x); | ||
|
|
||
| uint16_t x_u = x_bits.uintval(); | ||
| uint16_t x_abs = x_u & 0x7fffU; | ||
|
|
||
| // When |x| <= 2^(-3), or |x| >= 11 * log10(2), or x is NaN. | ||
| if (LIBC_UNLIKELY(x_abs <= 0x3000U || x_abs >= 0x429fU)) { | ||
| // exp10m1(NaN) = NaN | ||
| if (x_bits.is_nan()) { | ||
| if (x_bits.is_signaling_nan()) { | ||
| fputil::raise_except_if_required(FE_INVALID); | ||
| return FPBits::quiet_nan().get_val(); | ||
| } | ||
|
|
||
| return x; | ||
| } | ||
|
|
||
| // When x >= 16 * log10(2). | ||
| if (x_u >= 0x44d1U && x_bits.is_pos()) { | ||
| // exp10m1(+inf) = +inf | ||
| if (x_bits.is_inf()) | ||
| return FPBits::inf().get_val(); | ||
|
|
||
| switch (fputil::quick_get_round()) { | ||
| case FE_TONEAREST: | ||
| case FE_UPWARD: | ||
| fputil::set_errno_if_required(ERANGE); | ||
| fputil::raise_except_if_required(FE_OVERFLOW | FE_INEXACT); | ||
| return FPBits::inf().get_val(); | ||
| default: | ||
| return FPBits::max_normal().get_val(); | ||
| } | ||
| } | ||
|
|
||
| // When x < -11 * log10(2). | ||
| if (x_u > 0xc29fU) { | ||
| // exp10m1(-inf) = -1 | ||
| if (x_bits.is_inf()) | ||
| return FPBits::one(Sign::NEG).get_val(); | ||
|
|
||
| // When x >= -0x1.ce4p+1, round(10^x - 1, HP, RN) = -0x1.ffcp-1. | ||
| if (x_u <= 0xc339U) { | ||
| return fputil::round_result_slightly_down( | ||
| static_cast<float16>(-0x1.ffcp-1)); | ||
| } | ||
|
|
||
| // When x < -0x1.ce4p+1, round(10^x - 1, HP, RN) = -1. | ||
| switch (fputil::quick_get_round()) { | ||
| case FE_TONEAREST: | ||
| case FE_DOWNWARD: | ||
| return FPBits::one(Sign::NEG).get_val(); | ||
| default: | ||
| return static_cast<float16>(-0x1.ffcp-1); | ||
| } | ||
| } | ||
|
|
||
| // When |x| <= 2^(-3). | ||
| if (x_abs <= 0x3000U) { | ||
| if (auto r = EXP10M1F16_EXCEPTS_LO.lookup(x_u); | ||
| LIBC_UNLIKELY(r.has_value())) | ||
| return r.value(); | ||
|
|
||
| float xf = x; | ||
| // Degree-5 minimax polynomial generated by Sollya with the following | ||
| // commands: | ||
| // > display = hexadecimal; | ||
| // > P = fpminimax((10^x - 1)/x, 4, [|SG...|], [-2^-3, 2^-3]); | ||
| // > x * P; | ||
| return static_cast<float16>( | ||
| xf * fputil::polyeval(xf, 0x1.26bb1cp+1f, 0x1.5351c8p+1f, | ||
| 0x1.04704p+1f, 0x1.2ce084p+0f, 0x1.14a6bep-1f)); | ||
| } | ||
| } | ||
|
|
||
| // When x is 1, 2, or 3. These are hard-to-round cases with exact results. | ||
| // 10^4 - 1 = 9'999 is not exactly representable as a float16, but luckily the | ||
| // polynomial approximation gives the correct result for x = 4 in all | ||
| // rounding modes. | ||
| if (LIBC_UNLIKELY((x_u & ~(0x3c00U | 0x4000U | 0x4200U | 0x4400U)) == 0)) { | ||
| switch (x_u) { | ||
| case 0x3c00U: // x = 1.0f16 | ||
| return static_cast<float16>(9.0); | ||
| case 0x4000U: // x = 2.0f16 | ||
| return static_cast<float16>(99.0); | ||
| case 0x4200U: // x = 3.0f16 | ||
| return static_cast<float16>(999.0); | ||
| } | ||
| } | ||
|
|
||
| if (auto r = EXP10M1F16_EXCEPTS_HI.lookup(x_u); LIBC_UNLIKELY(r.has_value())) | ||
| return r.value(); | ||
|
|
||
| // exp10(x) = exp2((hi + mid) * log2(10)) * exp10(lo) | ||
| auto [exp2_hi_mid, exp10_lo] = exp10_range_reduction(x); | ||
| // exp10m1(x) = exp2((hi + mid) * log2(lo)) * exp10(lo) - 1 | ||
| return static_cast<float16>( | ||
| fputil::multiply_add(exp2_hi_mid, exp10_lo, -1.0f)); | ||
| } | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| //===-- Half-precision 2^x - 1 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/exp2m1f16.h" | ||
| #include "expxf16.h" | ||
| #include "hdr/errno_macros.h" | ||
| #include "hdr/fenv_macros.h" | ||
| #include "src/__support/FPUtil/FEnvImpl.h" | ||
| #include "src/__support/FPUtil/FPBits.h" | ||
| #include "src/__support/FPUtil/PolyEval.h" | ||
| #include "src/__support/FPUtil/except_value_utils.h" | ||
| #include "src/__support/FPUtil/multiply_add.h" | ||
| #include "src/__support/FPUtil/rounding_mode.h" | ||
| #include "src/__support/common.h" | ||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/optimization.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| static constexpr fputil::ExceptValues<float16, 6> EXP2M1F16_EXCEPTS_LO = {{ | ||
| // (input, RZ output, RU offset, RD offset, RN offset) | ||
| // x = 0x1.cf4p-13, exp2m1f16(x) = 0x1.41p-13 (RZ) | ||
| {0x0b3dU, 0x0904U, 1U, 0U, 1U}, | ||
| // x = 0x1.4fcp-12, exp2m1f16(x) = 0x1.d14p-13 (RZ) | ||
| {0x0d3fU, 0x0b45U, 1U, 0U, 1U}, | ||
| // x = 0x1.63p-11, exp2m1f16(x) = 0x1.ec4p-12 (RZ) | ||
| {0x118cU, 0x0fb1U, 1U, 0U, 0U}, | ||
| // x = 0x1.6fp-7, exp2m1f16(x) = 0x1.fe8p-8 (RZ) | ||
| {0x21bcU, 0x1ffaU, 1U, 0U, 1U}, | ||
| // x = -0x1.c6p-10, exp2m1f16(x) = -0x1.3a8p-10 (RZ) | ||
| {0x9718U, 0x94eaU, 0U, 1U, 0U}, | ||
| // x = -0x1.cfcp-10, exp2m1f16(x) = -0x1.414p-10 (RZ) | ||
| {0x973fU, 0x9505U, 0U, 1U, 0U}, | ||
| }}; | ||
|
|
||
| #ifdef LIBC_TARGET_CPU_HAS_FMA | ||
| static constexpr size_t N_EXP2M1F16_EXCEPTS_HI = 6; | ||
| #else | ||
| static constexpr size_t N_EXP2M1F16_EXCEPTS_HI = 7; | ||
| #endif | ||
|
|
||
| static constexpr fputil::ExceptValues<float16, N_EXP2M1F16_EXCEPTS_HI> | ||
| EXP2M1F16_EXCEPTS_HI = {{ | ||
| // (input, RZ output, RU offset, RD offset, RN offset) | ||
| // x = 0x1.e58p-3, exp2m1f16(x) = 0x1.6dcp-3 (RZ) | ||
| {0x3396U, 0x31b7U, 1U, 0U, 0U}, | ||
| #ifndef LIBC_TARGET_CPU_HAS_FMA | ||
| // x = 0x1.2e8p-2, exp2m1f16(x) = 0x1.d14p-3 (RZ) | ||
| {0x34baU, 0x3345U, 1U, 0U, 0U}, | ||
| #endif | ||
| // x = 0x1.ad8p-2, exp2m1f16(x) = 0x1.598p-2 (RZ) | ||
| {0x36b6U, 0x3566U, 1U, 0U, 0U}, | ||
| #ifdef LIBC_TARGET_CPU_HAS_FMA | ||
| // x = 0x1.edcp-2, exp2m1f16(x) = 0x1.964p-2 (RZ) | ||
| {0x37b7U, 0x3659U, 1U, 0U, 1U}, | ||
| #endif | ||
| // x = -0x1.804p-3, exp2m1f16(x) = -0x1.f34p-4 (RZ) | ||
| {0xb201U, 0xafcdU, 0U, 1U, 1U}, | ||
| // x = -0x1.f3p-3, exp2m1f16(x) = -0x1.3e4p-3 (RZ) | ||
| {0xb3ccU, 0xb0f9U, 0U, 1U, 0U}, | ||
| // x = -0x1.294p-1, exp2m1f16(x) = -0x1.53p-2 (RZ) | ||
| {0xb8a5U, 0xb54cU, 0U, 1U, 1U}, | ||
| #ifndef LIBC_TARGET_CPU_HAS_FMA | ||
| // x = -0x1.a34p-1, exp2m1f16(x) = -0x1.bb4p-2 (RZ) | ||
| {0xba8dU, 0xb6edU, 0U, 1U, 1U}, | ||
| #endif | ||
| }}; | ||
|
|
||
| LLVM_LIBC_FUNCTION(float16, exp2m1f16, (float16 x)) { | ||
| using FPBits = fputil::FPBits<float16>; | ||
| FPBits x_bits(x); | ||
|
|
||
| uint16_t x_u = x_bits.uintval(); | ||
| uint16_t x_abs = x_u & 0x7fffU; | ||
|
|
||
| // When |x| <= 2^(-3), or |x| >= 11, or x is NaN. | ||
| if (LIBC_UNLIKELY(x_abs <= 0x3000U || x_abs >= 0x4980U)) { | ||
| // exp2m1(NaN) = NaN | ||
| if (x_bits.is_nan()) { | ||
| if (x_bits.is_signaling_nan()) { | ||
| fputil::raise_except_if_required(FE_INVALID); | ||
| return FPBits::quiet_nan().get_val(); | ||
| } | ||
|
|
||
| return x; | ||
| } | ||
|
|
||
| // When x >= 16. | ||
| if (x_u >= 0x4c00 && x_bits.is_pos()) { | ||
| // exp2m1(+inf) = +inf | ||
| if (x_bits.is_inf()) | ||
| return FPBits::inf().get_val(); | ||
|
|
||
| switch (fputil::quick_get_round()) { | ||
| case FE_TONEAREST: | ||
| case FE_UPWARD: | ||
| fputil::set_errno_if_required(ERANGE); | ||
| fputil::raise_except_if_required(FE_OVERFLOW | FE_INEXACT); | ||
| return FPBits::inf().get_val(); | ||
| default: | ||
| return FPBits::max_normal().get_val(); | ||
| } | ||
| } | ||
|
|
||
| // When x < -11. | ||
| if (x_u > 0xc980U) { | ||
| // exp2m1(-inf) = -1 | ||
| if (x_bits.is_inf()) | ||
| return FPBits::one(Sign::NEG).get_val(); | ||
|
|
||
| // When -12 < x < -11, round(2^x - 1, HP, RN) = -0x1.ffcp-1. | ||
| if (x_u < 0xca00U) { | ||
| return fputil::round_result_slightly_down( | ||
| static_cast<float16>(-0x1.ffcp-1)); | ||
| } | ||
|
|
||
| // When x <= -12, round(2^x - 1, HP, RN) = -1. | ||
| switch (fputil::quick_get_round()) { | ||
| case FE_TONEAREST: | ||
| case FE_DOWNWARD: | ||
| return FPBits::one(Sign::NEG).get_val(); | ||
| default: | ||
| return static_cast<float16>(-0x1.ffcp-1); | ||
| } | ||
| } | ||
|
|
||
| // When |x| <= 2^(-3). | ||
| if (x_abs <= 0x3000U) { | ||
| if (auto r = EXP2M1F16_EXCEPTS_LO.lookup(x_u); | ||
| LIBC_UNLIKELY(r.has_value())) | ||
| return r.value(); | ||
|
|
||
| float xf = x; | ||
| // Degree-5 minimax polynomial generated by Sollya with the following | ||
| // commands: | ||
| // > display = hexadecimal; | ||
| // > P = fpminimax((2^x - 1)/x, 4, [|SG...|], [-2^-3, 2^-3]); | ||
| // > x * P; | ||
| return static_cast<float16>( | ||
| xf * fputil::polyeval(xf, 0x1.62e43p-1f, 0x1.ebfbdep-3f, | ||
| 0x1.c6af88p-5f, 0x1.3b45d6p-7f, | ||
| 0x1.641e7cp-10f)); | ||
| } | ||
| } | ||
|
|
||
| if (auto r = EXP2M1F16_EXCEPTS_HI.lookup(x_u); LIBC_UNLIKELY(r.has_value())) | ||
| return r.value(); | ||
|
|
||
| // exp2(x) = exp2(hi + mid) * exp2(lo) | ||
| auto [exp2_hi_mid, exp2_lo] = exp2_range_reduction(x); | ||
| // exp2m1(x) = exp2(hi + mid) * exp2(lo) - 1 | ||
| return static_cast<float16>( | ||
| fputil::multiply_add(exp2_hi_mid, exp2_lo, -1.0f)); | ||
| } | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,163 @@ | ||
| //===-- Half-precision log10(x) 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/log10f16.h" | ||
| #include "expxf16.h" | ||
| #include "hdr/errno_macros.h" | ||
| #include "hdr/fenv_macros.h" | ||
| #include "src/__support/FPUtil/FEnvImpl.h" | ||
| #include "src/__support/FPUtil/FPBits.h" | ||
| #include "src/__support/FPUtil/PolyEval.h" | ||
| #include "src/__support/FPUtil/except_value_utils.h" | ||
| #include "src/__support/FPUtil/multiply_add.h" | ||
| #include "src/__support/common.h" | ||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/optimization.h" | ||
| #include "src/__support/macros/properties/cpu_features.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| #ifdef LIBC_TARGET_CPU_HAS_FMA | ||
| static constexpr size_t N_LOG10F16_EXCEPTS = 11; | ||
| #else | ||
| static constexpr size_t N_LOG10F16_EXCEPTS = 17; | ||
| #endif | ||
|
|
||
| static constexpr fputil::ExceptValues<float16, N_LOG10F16_EXCEPTS> | ||
| LOG10F16_EXCEPTS = {{ | ||
| // (input, RZ output, RU offset, RD offset, RN offset) | ||
| // x = 0x1.e3cp-3, log10f16(x) = -0x1.40cp-1 (RZ) | ||
| {0x338fU, 0xb903U, 0U, 1U, 0U}, | ||
| // x = 0x1.fep-3, log10f16(x) = -0x1.35p-1 (RZ) | ||
| {0x33f8U, 0xb8d4U, 0U, 1U, 1U}, | ||
| #ifndef LIBC_TARGET_CPU_HAS_FMA | ||
| // x = 0x1.394p-1, log10f16(x) = -0x1.b4cp-3 (RZ) | ||
| {0x38e5U, 0xb2d3U, 0U, 1U, 1U}, | ||
| #endif | ||
| // x = 0x1.ea8p-1, log10f16(x) = -0x1.31p-6 (RZ) | ||
| {0x3baaU, 0xa4c4U, 0U, 1U, 1U}, | ||
| // x = 0x1.ebp-1, log10f16(x) = -0x1.29cp-6 (RZ) | ||
| {0x3bacU, 0xa4a7U, 0U, 1U, 1U}, | ||
| // x = 0x1.f3p-1, log10f16(x) = -0x1.6dcp-7 (RZ) | ||
| {0x3bccU, 0xa1b7U, 0U, 1U, 1U}, | ||
| // x = 0x1.f38p-1, log10f16(x) = -0x1.5f8p-7 (RZ) | ||
| #ifndef LIBC_TARGET_CPU_HAS_FMA | ||
| {0x3bceU, 0xa17eU, 0U, 1U, 1U}, | ||
| // x = 0x1.fd8p-1, log10f16(x) = -0x1.168p-9 (RZ) | ||
| {0x3bf6U, 0x985aU, 0U, 1U, 1U}, | ||
| // x = 0x1.ff8p-1, log10f16(x) = -0x1.bccp-12 (RZ) | ||
| {0x3bfeU, 0x8ef3U, 0U, 1U, 1U}, | ||
| // x = 0x1.374p+0, log10f16(x) = 0x1.5b8p-4 (RZ) | ||
| {0x3cddU, 0x2d6eU, 1U, 0U, 1U}, | ||
| // x = 0x1.3ecp+1, log10f16(x) = 0x1.958p-2 (RZ) | ||
| {0x40fbU, 0x3656U, 1U, 0U, 1U}, | ||
| #endif | ||
| // x = 0x1.4p+3, log10f16(x) = 0x1p+0 (RZ) | ||
| {0x4900U, 0x3c00U, 0U, 0U, 0U}, | ||
| // x = 0x1.9p+6, log10f16(x) = 0x1p+1 (RZ) | ||
| {0x5640U, 0x4000U, 0U, 0U, 0U}, | ||
| // x = 0x1.f84p+6, log10f16(x) = 0x1.0ccp+1 (RZ) | ||
| {0x57e1U, 0x4033U, 1U, 0U, 0U}, | ||
| // x = 0x1.f4p+9, log10f16(x) = 0x1.8p+1 (RZ) | ||
| {0x63d0U, 0x4200U, 0U, 0U, 0U}, | ||
| // x = 0x1.388p+13, log10f16(x) = 0x1p+2 (RZ) | ||
| {0x70e2U, 0x4400U, 0U, 0U, 0U}, | ||
| // x = 0x1.674p+13, log10f16(x) = 0x1.03cp+2 (RZ) | ||
| {0x719dU, 0x440fU, 1U, 0U, 0U}, | ||
| }}; | ||
|
|
||
| LLVM_LIBC_FUNCTION(float16, log10f16, (float16 x)) { | ||
| using FPBits = fputil::FPBits<float16>; | ||
| FPBits x_bits(x); | ||
|
|
||
| uint16_t x_u = x_bits.uintval(); | ||
|
|
||
| // If x <= 0, or x is 1, or x is +inf, or x is NaN. | ||
| if (LIBC_UNLIKELY(x_u == 0U || x_u == 0x3c00U || x_u >= 0x7c00U)) { | ||
| // log10(NaN) = NaN | ||
| if (x_bits.is_nan()) { | ||
| if (x_bits.is_signaling_nan()) { | ||
| fputil::raise_except_if_required(FE_INVALID); | ||
| return FPBits::quiet_nan().get_val(); | ||
| } | ||
|
|
||
| return x; | ||
| } | ||
|
|
||
| // log10(+/-0) = −inf | ||
| if ((x_u & 0x7fffU) == 0U) { | ||
| fputil::raise_except_if_required(FE_DIVBYZERO); | ||
| return FPBits::inf(Sign::NEG).get_val(); | ||
| } | ||
|
|
||
| if (x_u == 0x3c00U) | ||
| return FPBits::zero().get_val(); | ||
|
|
||
| // When x < 0. | ||
| if (x_u > 0x8000U) { | ||
| fputil::set_errno_if_required(EDOM); | ||
| fputil::raise_except_if_required(FE_INVALID); | ||
| return FPBits::quiet_nan().get_val(); | ||
| } | ||
|
|
||
| // log10(+inf) = +inf | ||
| return FPBits::inf().get_val(); | ||
| } | ||
|
|
||
| if (auto r = LOG10F16_EXCEPTS.lookup(x_u); LIBC_UNLIKELY(r.has_value())) | ||
| return r.value(); | ||
|
|
||
| // To compute log10(x), we perform the following range reduction: | ||
| // x = 2^m * 1.mant, | ||
| // log10(x) = m * log10(2) + log10(1.mant). | ||
| // To compute log10(1.mant), let f be the highest 6 bits including the hidden | ||
| // bit, and d be the difference (1.mant - f), i.e., the remaining 5 bits of | ||
| // the mantissa, then: | ||
| // log10(1.mant) = log10(f) + log10(1.mant / f) | ||
| // = log10(f) + log10(1 + d/f) | ||
| // since d/f is sufficiently small. | ||
| // We store log10(f) and 1/f in the lookup tables LOG10F_F and ONE_OVER_F | ||
| // respectively. | ||
|
|
||
| int m = -FPBits::EXP_BIAS; | ||
|
|
||
| // When x is subnormal. | ||
| if ((x_u & FPBits::EXP_MASK) == 0U) { | ||
| // Normalize x. | ||
| x_bits = FPBits(x_bits.get_val() * | ||
| static_cast<float16>((1U << FPBits::FRACTION_LEN))); | ||
| x_u = x_bits.uintval(); | ||
| m -= FPBits::FRACTION_LEN; | ||
| } | ||
|
|
||
| uint16_t mant = x_bits.get_mantissa(); | ||
| // Leading 10 - 5 = 5 bits of the mantissa. | ||
| int f = mant >> 5; | ||
| // Unbiased exponent. | ||
| m += x_u >> FPBits::FRACTION_LEN; | ||
|
|
||
| // Set bits to 1.mant instead of 2^m * 1.mant. | ||
| x_bits.set_biased_exponent(FPBits::EXP_BIAS); | ||
| float mant_f = x_bits.get_val(); | ||
| // v = 1.mant * 1/f - 1 = d/f | ||
| float v = fputil::multiply_add(mant_f, ONE_OVER_F[f], -1.0f); | ||
|
|
||
| // Degree-3 minimax polynomial generated by Sollya with the following | ||
| // commands: | ||
| // > display = hexadecimal; | ||
| // > P = fpminimax(log10(1 + x)/x, 2, [|SG...|], [-2^-5, 2^-5]); | ||
| // > x * P; | ||
| float log10p1_d_over_f = | ||
| v * fputil::polyeval(v, 0x1.bcb7bp-2f, -0x1.bce168p-3f, 0x1.28acb8p-3f); | ||
| // log10(1.mant) = log10(f) + log10(1 + d/f) | ||
| float log10_1_mant = LOG10F_F[f] + log10p1_d_over_f; | ||
| return static_cast<float16>( | ||
| fputil::multiply_add(static_cast<float>(m), LOG10F_2, log10_1_mant)); | ||
| } | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| //===-- Implementation of log2f16 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/log2f16.h" | ||
| #include "expxf16.h" | ||
| #include "hdr/errno_macros.h" | ||
| #include "hdr/fenv_macros.h" | ||
| #include "src/__support/FPUtil/FEnvImpl.h" | ||
| #include "src/__support/FPUtil/FPBits.h" | ||
| #include "src/__support/FPUtil/PolyEval.h" | ||
| #include "src/__support/FPUtil/except_value_utils.h" | ||
| #include "src/__support/FPUtil/multiply_add.h" | ||
| #include "src/__support/common.h" | ||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/optimization.h" | ||
| #include "src/__support/macros/properties/cpu_features.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| #ifdef LIBC_TARGET_CPU_HAS_FMA | ||
| static constexpr size_t N_LOG2F16_EXCEPTS = 2; | ||
| #else | ||
| static constexpr size_t N_LOG2F16_EXCEPTS = 9; | ||
| #endif | ||
|
|
||
| static constexpr fputil::ExceptValues<float16, N_LOG2F16_EXCEPTS> | ||
| LOG2F16_EXCEPTS = {{ | ||
| #ifndef LIBC_TARGET_CPU_HAS_FMA | ||
| // x = 0x1.224p-1, log2f16(x) = -0x1.a34p-1 (RZ) | ||
| {0x3889U, 0xba8dU, 0U, 1U, 0U}, | ||
| // x = 0x1.e34p-1, log2f16(x) = -0x1.558p-4 (RZ) | ||
| {0x3b8dU, 0xad56U, 0U, 1U, 0U}, | ||
| #endif | ||
| // x = 0x1.e8cp-1, log2f16(x) = -0x1.128p-4 (RZ) | ||
| {0x3ba3U, 0xac4aU, 0U, 1U, 0U}, | ||
| #ifndef LIBC_TARGET_CPU_HAS_FMA | ||
| // x = 0x1.f98p-1, log2f16(x) = -0x1.2ep-6 (RZ) | ||
| {0x3be6U, 0xa4b8U, 0U, 1U, 0U}, | ||
| // x = 0x1.facp-1, log2f16(x) = -0x1.e7p-7 (RZ) | ||
| {0x3bebU, 0xa39cU, 0U, 1U, 1U}, | ||
| #endif | ||
| // x = 0x1.fb4p-1, log2f16(x) = -0x1.b88p-7 (RZ) | ||
| {0x3bedU, 0xa2e2U, 0U, 1U, 1U}, | ||
| #ifndef LIBC_TARGET_CPU_HAS_FMA | ||
| // x = 0x1.fecp-1, log2f16(x) = -0x1.cep-9 (RZ) | ||
| {0x3bfbU, 0x9b38U, 0U, 1U, 1U}, | ||
| // x = 0x1.ffcp-1, log2f16(x) = -0x1.714p-11 (RZ) | ||
| {0x3bffU, 0x91c5U, 0U, 1U, 1U}, | ||
| // x = 0x1.224p+0, log2f16(x) = 0x1.72cp-3 (RZ) | ||
| {0x3c89U, 0x31cbU, 1U, 0U, 1U}, | ||
| #endif | ||
| }}; | ||
|
|
||
| LLVM_LIBC_FUNCTION(float16, log2f16, (float16 x)) { | ||
| using FPBits = fputil::FPBits<float16>; | ||
| FPBits x_bits(x); | ||
|
|
||
| uint16_t x_u = x_bits.uintval(); | ||
|
|
||
| // If x <= 0, or x is 1, or x is +inf, or x is NaN. | ||
| if (LIBC_UNLIKELY(x_u == 0U || x_u == 0x3c00U || x_u >= 0x7c00U)) { | ||
| // log2(NaN) = NaN | ||
| if (x_bits.is_nan()) { | ||
| if (x_bits.is_signaling_nan()) { | ||
| fputil::raise_except_if_required(FE_INVALID); | ||
| return FPBits::quiet_nan().get_val(); | ||
| } | ||
|
|
||
| return x; | ||
| } | ||
|
|
||
| // log2(+/-0) = −inf | ||
| if ((x_u & 0x7fffU) == 0U) { | ||
| fputil::raise_except_if_required(FE_DIVBYZERO); | ||
| return FPBits::inf(Sign::NEG).get_val(); | ||
| } | ||
|
|
||
| if (x_u == 0x3c00U) | ||
| return FPBits::zero().get_val(); | ||
|
|
||
| // When x < 0. | ||
| if (x_u > 0x8000U) { | ||
| fputil::set_errno_if_required(EDOM); | ||
| fputil::raise_except_if_required(FE_INVALID); | ||
| return FPBits::quiet_nan().get_val(); | ||
| } | ||
|
|
||
| // log2(+inf) = +inf | ||
| return FPBits::inf().get_val(); | ||
| } | ||
|
|
||
| if (auto r = LOG2F16_EXCEPTS.lookup(x_u); LIBC_UNLIKELY(r.has_value())) | ||
| return r.value(); | ||
|
|
||
| // To compute log2(x), we perform the following range reduction: | ||
| // x = 2^m * 1.mant, | ||
| // log2(x) = m + log2(1.mant). | ||
| // To compute log2(1.mant), let f be the highest 6 bits including the hidden | ||
| // bit, and d be the difference (1.mant - f), i.e., the remaining 5 bits of | ||
| // the mantissa, then: | ||
| // log2(1.mant) = log2(f) + log2(1.mant / f) | ||
| // = log2(f) + log2(1 + d/f) | ||
| // since d/f is sufficiently small. | ||
| // We store log2(f) and 1/f in the lookup tables LOG2F_F and ONE_OVER_F | ||
| // respectively. | ||
|
|
||
| int m = -FPBits::EXP_BIAS; | ||
|
|
||
| // When x is subnormal. | ||
| if ((x_u & FPBits::EXP_MASK) == 0U) { | ||
| // Normalize x. | ||
| x_bits = FPBits(x_bits.get_val() * | ||
| static_cast<float16>((1U << FPBits::FRACTION_LEN))); | ||
| x_u = x_bits.uintval(); | ||
| m -= FPBits::FRACTION_LEN; | ||
| } | ||
|
|
||
| uint16_t mant = x_bits.get_mantissa(); | ||
| // Leading 10 - 5 = 5 bits of the mantissa. | ||
| int f = mant >> 5; | ||
| // Unbiased exponent. | ||
| m += x_u >> FPBits::FRACTION_LEN; | ||
|
|
||
| // Set bits to 1.mant instead of 2^m * 1.mant. | ||
| x_bits.set_biased_exponent(FPBits::EXP_BIAS); | ||
| float mant_f = x_bits.get_val(); | ||
| // v = 1.mant * 1/f - 1 = d/f | ||
| float v = fputil::multiply_add(mant_f, ONE_OVER_F[f], -1.0f); | ||
|
|
||
| // Degree-3 minimax polynomial generated by Sollya with the following | ||
| // commands: | ||
| // > display = hexadecimal; | ||
| // > P = fpminimax(log2(1 + x)/x, 2, [|SG...|], [-2^-5, 2^-5]); | ||
| // > x * P; | ||
| float log2p1_d_over_f = | ||
| v * fputil::polyeval(v, 0x1.715476p+0f, -0x1.71771ap-1f, 0x1.ecb38ep-2f); | ||
| // log2(1.mant) = log2(f) + log2(1 + d/f) | ||
| float log2_1_mant = LOG2F_F[f] + log2p1_d_over_f; | ||
| return static_cast<float16>(static_cast<float>(m) + log2_1_mant); | ||
| } | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| //===-- Half-precision log(x) 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/logf16.h" | ||
| #include "expxf16.h" | ||
| #include "hdr/errno_macros.h" | ||
| #include "hdr/fenv_macros.h" | ||
| #include "src/__support/CPP/array.h" | ||
| #include "src/__support/FPUtil/FEnvImpl.h" | ||
| #include "src/__support/FPUtil/FPBits.h" | ||
| #include "src/__support/FPUtil/PolyEval.h" | ||
| #include "src/__support/FPUtil/except_value_utils.h" | ||
| #include "src/__support/FPUtil/multiply_add.h" | ||
| #include "src/__support/common.h" | ||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/optimization.h" | ||
| #include "src/__support/macros/properties/cpu_features.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| #ifdef LIBC_TARGET_CPU_HAS_FMA | ||
| static constexpr size_t N_LOGF16_EXCEPTS = 5; | ||
| #else | ||
| static constexpr size_t N_LOGF16_EXCEPTS = 11; | ||
| #endif | ||
|
|
||
| static constexpr fputil::ExceptValues<float16, N_LOGF16_EXCEPTS> | ||
| LOGF16_EXCEPTS = {{ | ||
| // (input, RZ output, RU offset, RD offset, RN offset) | ||
| #ifndef LIBC_TARGET_CPU_HAS_FMA | ||
| // x = 0x1.61cp-13, logf16(x) = -0x1.16p+3 (RZ) | ||
| {0x0987U, 0xc858U, 0U, 1U, 0U}, | ||
| // x = 0x1.f2p-12, logf16(x) = -0x1.e98p+2 (RZ) | ||
| {0x0fc8U, 0xc7a6U, 0U, 1U, 1U}, | ||
| // x = 0x1.4d4p-9, logf16(x) = -0x1.7e4p+2 (RZ) | ||
| #endif | ||
| // x = 0x1.4d4p-9, logf16(x) = -0x1.7e4p+2 (RZ) | ||
| {0x1935U, 0xc5f9U, 0U, 1U, 0U}, | ||
| // x = 0x1.5ep-8, logf16(x) = -0x1.4ecp+2 (RZ) | ||
| {0x1d78U, 0xc53bU, 0U, 1U, 0U}, | ||
| #ifndef LIBC_TARGET_CPU_HAS_FMA | ||
| // x = 0x1.fdp-1, logf16(x) = -0x1.81p-8 (RZ) | ||
| {0x3bf4U, 0x9e04U, 0U, 1U, 1U}, | ||
| // x = 0x1.fep-1, logf16(x) = -0x1.008p-8 (RZ) | ||
| {0x3bf8U, 0x9c02U, 0U, 1U, 0U}, | ||
| #endif | ||
| // x = 0x1.ffp-1, logf16(x) = -0x1.004p-9 (RZ) | ||
| {0x3bfcU, 0x9801U, 0U, 1U, 0U}, | ||
| // x = 0x1.ff8p-1, logf16(x) = -0x1p-10 (RZ) | ||
| {0x3bfeU, 0x9400U, 0U, 1U, 1U}, | ||
| #ifdef LIBC_TARGET_CPU_HAS_FMA | ||
| // x = 0x1.4c4p+1, logf16(x) = 0x1.e84p-1 (RZ) | ||
| {0x4131U, 0x3ba1U, 1U, 0U, 1U}, | ||
| #else | ||
| // x = 0x1.75p+2, logf16(x) = 0x1.c34p+0 (RZ) | ||
| {0x45d4U, 0x3f0dU, 1U, 0U, 0U}, | ||
| // x = 0x1.75p+2, logf16(x) = 0x1.c34p+0 (RZ) | ||
| {0x45d4U, 0x3f0dU, 1U, 0U, 0U}, | ||
| // x = 0x1.d5p+9, logf16(x) = 0x1.b5cp+2 (RZ) | ||
| {0x6354U, 0x46d7U, 1U, 0U, 1U}, | ||
| #endif | ||
| }}; | ||
|
|
||
| LLVM_LIBC_FUNCTION(float16, logf16, (float16 x)) { | ||
| using FPBits = fputil::FPBits<float16>; | ||
| FPBits x_bits(x); | ||
|
|
||
| uint16_t x_u = x_bits.uintval(); | ||
|
|
||
| // If x <= 0, or x is 1, or x is +inf, or x is NaN. | ||
| if (LIBC_UNLIKELY(x_u == 0U || x_u == 0x3c00U || x_u >= 0x7c00U)) { | ||
| // log(NaN) = NaN | ||
| if (x_bits.is_nan()) { | ||
| if (x_bits.is_signaling_nan()) { | ||
| fputil::raise_except_if_required(FE_INVALID); | ||
| return FPBits::quiet_nan().get_val(); | ||
| } | ||
|
|
||
| return x; | ||
| } | ||
|
|
||
| // log(+/-0) = −inf | ||
| if ((x_u & 0x7fffU) == 0U) { | ||
| fputil::raise_except_if_required(FE_DIVBYZERO); | ||
| return FPBits::inf(Sign::NEG).get_val(); | ||
| } | ||
|
|
||
| if (x_u == 0x3c00U) | ||
| return FPBits::zero().get_val(); | ||
|
|
||
| // When x < 0. | ||
| if (x_u > 0x8000) { | ||
| fputil::set_errno_if_required(EDOM); | ||
| fputil::raise_except_if_required(FE_INVALID); | ||
| return FPBits::quiet_nan().get_val(); | ||
| } | ||
|
|
||
| // log(+inf) = +inf | ||
| return FPBits::inf().get_val(); | ||
| } | ||
|
|
||
| if (auto r = LOGF16_EXCEPTS.lookup(x_u); LIBC_UNLIKELY(r.has_value())) | ||
| return r.value(); | ||
|
|
||
| // To compute log(x), we perform the following range reduction: | ||
| // x = 2^m * 1.mant, | ||
| // log(x) = m * log(2) + log(1.mant). | ||
| // To compute log(1.mant), let f be the highest 6 bits including the hidden | ||
| // bit, and d be the difference (1.mant - f), i.e., the remaining 5 bits of | ||
| // the mantissa, then: | ||
| // log(1.mant) = log(f) + log(1.mant / f) | ||
| // = log(f) + log(1 + d/f) | ||
| // since d/f is sufficiently small. | ||
| // We store log(f) and 1/f in the lookup tables LOGF_F and ONE_OVER_F | ||
| // respectively. | ||
|
|
||
| int m = -FPBits::EXP_BIAS; | ||
|
|
||
| // When x is subnormal. | ||
| if ((x_u & FPBits::EXP_MASK) == 0U) { | ||
| // Normalize x. | ||
| x_bits = FPBits(x_bits.get_val() * | ||
| static_cast<float16>((1U << FPBits::FRACTION_LEN))); | ||
| x_u = x_bits.uintval(); | ||
| m -= FPBits::FRACTION_LEN; | ||
| } | ||
|
|
||
| uint16_t mant = x_bits.get_mantissa(); | ||
| // Leading 10 - 5 = 5 bits of the mantissa. | ||
| int f = mant >> 5; | ||
| // Unbiased exponent. | ||
| m += x_u >> FPBits::FRACTION_LEN; | ||
|
|
||
| // Set bits to 1.mant instead of 2^m * 1.mant. | ||
| x_bits.set_biased_exponent(FPBits::EXP_BIAS); | ||
| float mant_f = x_bits.get_val(); | ||
| // v = 1.mant * 1/f - 1 = d/f | ||
| float v = fputil::multiply_add(mant_f, ONE_OVER_F[f], -1.0f); | ||
|
|
||
| // Degree-3 minimax polynomial generated by Sollya with the following | ||
| // commands: | ||
| // > display = hexadecimal; | ||
| // > P = fpminimax(log(1 + x)/x, 2, [|SG...|], [-2^-5, 2^-5]); | ||
| // > x * P; | ||
| float log1p_d_over_f = | ||
| v * fputil::polyeval(v, 0x1p+0f, -0x1.001804p-1f, 0x1.557ef6p-2f); | ||
| // log(1.mant) = log(f) + log(1 + d/f) | ||
| float log_1_mant = LOGF_F[f] + log1p_d_over_f; | ||
| return static_cast<float16>( | ||
| fputil::multiply_add(static_cast<float>(m), LOGF_2, log_1_mant)); | ||
| } | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| //===-- Half-precision sinh(x) 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/sinhf16.h" | ||
| #include "expxf16.h" | ||
| #include "hdr/errno_macros.h" | ||
| #include "hdr/fenv_macros.h" | ||
| #include "src/__support/FPUtil/FEnvImpl.h" | ||
| #include "src/__support/FPUtil/FPBits.h" | ||
| #include "src/__support/FPUtil/except_value_utils.h" | ||
| #include "src/__support/FPUtil/rounding_mode.h" | ||
| #include "src/__support/common.h" | ||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/optimization.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| static constexpr fputil::ExceptValues<float16, 16> SINHF16_EXCEPTS_POS = {{ | ||
| // x = 0x1.714p-5, sinhf16(x) = 0x1.714p-5 (RZ) | ||
| {0x29c5U, 0x29c5U, 1U, 0U, 1U}, | ||
| // x = 0x1.25p-4, sinhf16(x) = 0x1.25p-4 (RZ) | ||
| {0x2c94U, 0x2c94U, 1U, 0U, 1U}, | ||
| // x = 0x1.f5p-4, sinhf16(x) = 0x1.f64p-4 (RZ) | ||
| {0x2fd4U, 0x2fd9U, 1U, 0U, 0U}, | ||
| // x = 0x1.b1cp-3, sinhf16(x) = 0x1.b4cp-3 (RZ) | ||
| {0x32c7U, 0x32d3U, 1U, 0U, 1U}, | ||
| // x = 0x1.6e8p-2, sinhf16(x) = 0x1.764p-2 (RZ) | ||
| {0x35baU, 0x35d9U, 1U, 0U, 1U}, | ||
| // x = 0x1.6b4p-1, sinhf16(x) = 0x1.8a4p-1 (RZ) | ||
| {0x39adU, 0x3a29U, 1U, 0U, 1U}, | ||
| // x = 0x1.a58p-1, sinhf16(x) = 0x1.d68p-1 (RZ) | ||
| {0x3a96U, 0x3b5aU, 1U, 0U, 1U}, | ||
| // x = 0x1.574p+0, sinhf16(x) = 0x1.c78p+0 (RZ) | ||
| {0x3d5dU, 0x3f1eU, 1U, 0U, 1U}, | ||
| // x = 0x1.648p+1, sinhf16(x) = 0x1.024p+3 (RZ) | ||
| {0x4192U, 0x4809U, 1U, 0U, 0U}, | ||
| // x = 0x1.cdcp+1, sinhf16(x) = 0x1.26cp+4 (RZ) | ||
| {0x4337U, 0x4c9bU, 1U, 0U, 0U}, | ||
| // x = 0x1.d0cp+1, sinhf16(x) = 0x1.2d8p+4 (RZ) | ||
| {0x4343U, 0x4cb6U, 1U, 0U, 1U}, | ||
| // x = 0x1.018p+2, sinhf16(x) = 0x1.bfp+4 (RZ) | ||
| {0x4406U, 0x4efcU, 1U, 0U, 0U}, | ||
| // x = 0x1.2fcp+2, sinhf16(x) = 0x1.cc4p+5 (RZ) | ||
| {0x44bfU, 0x5331U, 1U, 0U, 1U}, | ||
| // x = 0x1.4ecp+2, sinhf16(x) = 0x1.75cp+6 (RZ) | ||
| {0x453bU, 0x55d7U, 1U, 0U, 0U}, | ||
| // x = 0x1.8a4p+2, sinhf16(x) = 0x1.d94p+7 (RZ) | ||
| {0x4629U, 0x5b65U, 1U, 0U, 1U}, | ||
| // x = 0x1.5fp+3, sinhf16(x) = 0x1.c54p+14 (RZ) | ||
| {0x497cU, 0x7715U, 1U, 0U, 1U}, | ||
| }}; | ||
|
|
||
| static constexpr fputil::ExceptValues<float16, 12> SINHF16_EXCEPTS_NEG = {{ | ||
| // x = -0x1.714p-5, sinhf16(x) = -0x1.714p-5 (RZ) | ||
| {0xa9c5U, 0xa9c5U, 0U, 1U, 1U}, | ||
| // x = -0x1.25p-4, sinhf16(x) = -0x1.25p-4 (RZ) | ||
| {0xac94U, 0xac94U, 0U, 1U, 1U}, | ||
| // x = -0x1.f5p-4, sinhf16(x) = -0x1.f64p-4 (RZ) | ||
| {0xafd4U, 0xafd9U, 0U, 1U, 0U}, | ||
| // x = -0x1.6e8p-2, sinhf16(x) = -0x1.764p-2 (RZ) | ||
| {0xb5baU, 0xb5d9U, 0U, 1U, 1U}, | ||
| // x = -0x1.a58p-1, sinhf16(x) = -0x1.d68p-1 (RZ) | ||
| {0xba96U, 0xbb5aU, 0U, 1U, 1U}, | ||
| // x = -0x1.cdcp+1, sinhf16(x) = -0x1.26cp+4 (RZ) | ||
| {0xc337U, 0xcc9bU, 0U, 1U, 0U}, | ||
| // x = -0x1.d0cp+1, sinhf16(x) = -0x1.2d8p+4 (RZ) | ||
| {0xc343U, 0xccb6U, 0U, 1U, 1U}, | ||
| // x = -0x1.018p+2, sinhf16(x) = -0x1.bfp+4 (RZ) | ||
| {0xc406U, 0xcefcU, 0U, 1U, 0U}, | ||
| // x = -0x1.2fcp+2, sinhf16(x) = -0x1.cc4p+5 (RZ) | ||
| {0xc4bfU, 0xd331U, 0U, 1U, 1U}, | ||
| // x = -0x1.4ecp+2, sinhf16(x) = -0x1.75cp+6 (RZ) | ||
| {0xc53bU, 0xd5d7U, 0U, 1U, 0U}, | ||
| // x = -0x1.8a4p+2, sinhf16(x) = -0x1.d94p+7 (RZ) | ||
| {0xc629U, 0xdb65U, 0U, 1U, 1U}, | ||
| // x = -0x1.5fp+3, sinhf16(x) = -0x1.c54p+14 (RZ) | ||
| {0xc97cU, 0xf715U, 0U, 1U, 1U}, | ||
| }}; | ||
|
|
||
| LLVM_LIBC_FUNCTION(float16, sinhf16, (float16 x)) { | ||
| using FPBits = fputil::FPBits<float16>; | ||
| FPBits x_bits(x); | ||
|
|
||
| uint16_t x_u = x_bits.uintval(); | ||
| uint16_t x_abs = x_u & 0x7fffU; | ||
|
|
||
| // When |x| = 0, or -2^(-14) <= x <= -2^(-9), or |x| >= asinh(2^16), or x is | ||
| // NaN. | ||
| if (LIBC_UNLIKELY(x_abs == 0U || (x_u >= 0x8400U && x_u <= 0xa400U) || | ||
| x_abs >= 0x49e5U)) { | ||
| // sinh(NaN) = NaN | ||
| if (x_bits.is_nan()) { | ||
| if (x_bits.is_signaling_nan()) { | ||
| fputil::raise_except_if_required(FE_INVALID); | ||
| return FPBits::quiet_nan().get_val(); | ||
| } | ||
|
|
||
| return x; | ||
| } | ||
|
|
||
| // sinh(+/-0) = sinh(+/-0) | ||
| if (x_abs == 0U) | ||
| return FPBits::zero(x_bits.sign()).get_val(); | ||
|
|
||
| // When |x| >= asinh(2^16). | ||
| if (x_abs >= 0x49e5U) { | ||
| // sinh(+/-inf) = +/-inf | ||
| if (x_bits.is_inf()) | ||
| return FPBits::inf(x_bits.sign()).get_val(); | ||
|
|
||
| int rounding_mode = fputil::quick_get_round(); | ||
| if (rounding_mode == FE_TONEAREST || | ||
| (x_bits.is_pos() && rounding_mode == FE_UPWARD) || | ||
| (x_bits.is_neg() && rounding_mode == FE_DOWNWARD)) { | ||
| fputil::set_errno_if_required(ERANGE); | ||
| fputil::raise_except_if_required(FE_OVERFLOW | FE_INEXACT); | ||
| return FPBits::inf(x_bits.sign()).get_val(); | ||
| } | ||
| return FPBits::max_normal(x_bits.sign()).get_val(); | ||
| } | ||
|
|
||
| // When -2^(-14) <= x <= -2^(-9). | ||
| if (fputil::fenv_is_round_down()) | ||
| return FPBits(static_cast<uint16_t>(x_u + 1)).get_val(); | ||
| return FPBits(static_cast<uint16_t>(x_u)).get_val(); | ||
| } | ||
|
|
||
| if (x_bits.is_pos()) { | ||
| if (auto r = SINHF16_EXCEPTS_POS.lookup(x_u); LIBC_UNLIKELY(r.has_value())) | ||
| return r.value(); | ||
| } else { | ||
| if (auto r = SINHF16_EXCEPTS_NEG.lookup(x_u); LIBC_UNLIKELY(r.has_value())) | ||
| return r.value(); | ||
| } | ||
|
|
||
| return eval_sinh_or_cosh</*IsSinh=*/true>(x); | ||
| } | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| //===-- Implementation of sqrtf16 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/sqrtf16.h" | ||
| #include "src/__support/FPUtil/sqrt.h" | ||
| #include "src/__support/common.h" | ||
| #include "src/__support/macros/config.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| LLVM_LIBC_FUNCTION(float16, sqrtf16, (float16 x)) { | ||
| return fputil::sqrt<float16>(x); | ||
| } | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| //===-- Half-precision tanh(x) 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/tanhf16.h" | ||
| #include "expxf16.h" | ||
| #include "hdr/fenv_macros.h" | ||
| #include "src/__support/CPP/array.h" | ||
| #include "src/__support/FPUtil/FEnvImpl.h" | ||
| #include "src/__support/FPUtil/FPBits.h" | ||
| #include "src/__support/FPUtil/PolyEval.h" | ||
| #include "src/__support/FPUtil/except_value_utils.h" | ||
| #include "src/__support/FPUtil/multiply_add.h" | ||
| #include "src/__support/FPUtil/nearest_integer.h" | ||
| #include "src/__support/FPUtil/rounding_mode.h" | ||
| #include "src/__support/common.h" | ||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/optimization.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| static constexpr fputil::ExceptValues<float16, 2> TANHF16_EXCEPTS = {{ | ||
| // x = 0x1.f54p+0, tanhf16(x) = 0x1.ecp-1 (RZ) | ||
| {0x3fd5U, 0x3bb0U, 1U, 0U, 0U}, | ||
| // x = -0x1.f54p+0, tanhf16(x) = -0x1.ecp-1 (RZ) | ||
| {0xbfd5U, 0xbbb0U, 0U, 1U, 0U}, | ||
| }}; | ||
|
|
||
| LLVM_LIBC_FUNCTION(float16, tanhf16, (float16 x)) { | ||
| using FPBits = fputil::FPBits<float16>; | ||
| FPBits x_bits(x); | ||
|
|
||
| uint16_t x_u = x_bits.uintval(); | ||
| uint16_t x_abs = x_u & 0x7fffU; | ||
|
|
||
| // When -2^(-14) <= x <= -2^(-9), or |x| <= 0x1.d2p-4, | ||
| // or |x| >= atanh(1 - 2^(-11)), or x is NaN. | ||
| if (LIBC_UNLIKELY((x_u >= 0x8400U && x_u <= 0x9800U) || x_abs <= 0x2f48U || | ||
| x_abs >= 0x4429U)) { | ||
| // tanh(NaN) = NaN | ||
| if (x_bits.is_nan()) { | ||
| if (x_bits.is_signaling_nan()) { | ||
| fputil::raise_except_if_required(FE_INVALID); | ||
| return FPBits::quiet_nan().get_val(); | ||
| } | ||
|
|
||
| return x; | ||
| } | ||
|
|
||
| // When -2^(-14) <= x <= -2^(-9). | ||
| if (x_u >= 0x8400U && x_u <= 0x9800U) { | ||
| switch (fputil::quick_get_round()) { | ||
| case FE_TONEAREST: | ||
| case FE_DOWNWARD: | ||
| return x; | ||
| default: | ||
| return FPBits(static_cast<uint16_t>(x_u - 1U)).get_val(); | ||
| } | ||
| } | ||
|
|
||
| // When |x| <= 0x1.d2p-4. | ||
| if (x_abs <= 0x2f48U) { | ||
| float xf = x; | ||
| float xf_sq = xf * xf; | ||
| // Degree-7 Taylor expansion generated by Sollya with the following | ||
| // commands: | ||
| // > taylor(tanh(x), 7, 0); | ||
| // > display = hexadecimal; | ||
| // > // For each coefficient: | ||
| // > round(/* put coefficient here */, SG, RN); | ||
| return static_cast<float16>( | ||
| xf * fputil::polyeval(xf_sq, 0x1p+0f, -0x1.555556p-2f, 0x1.111112p-3f, | ||
| -0x1.ba1ba2p-5f)); | ||
| } | ||
|
|
||
| // tanh(+/-inf) = +/-1 | ||
| if (x_bits.is_inf()) | ||
| return FPBits::one(x_bits.sign()).get_val(); | ||
|
|
||
| // When |x| >= atanh(1 - 2^(-11)). | ||
| fputil::raise_except_if_required(FE_INEXACT); | ||
|
|
||
| int rounding_mode = fputil::quick_get_round(); | ||
| if ((rounding_mode == FE_TONEAREST && x_abs >= 0x4482U) || | ||
| (rounding_mode == FE_UPWARD && x_bits.is_pos()) || | ||
| (rounding_mode == FE_DOWNWARD && x_bits.is_neg())) { | ||
| return FPBits::one(x_bits.sign()).get_val(); | ||
| } | ||
| if (x_bits.is_pos()) | ||
| return static_cast<float16>(0x1.ffcp-1); | ||
| return static_cast<float16>(-0x1.ffcp-1); | ||
| } | ||
|
|
||
| if (auto r = TANHF16_EXCEPTS.lookup(x_u); LIBC_UNLIKELY(r.has_value())) | ||
| return r.value(); | ||
|
|
||
| // For atanh(-1 + 2^(-11)) < x < atanh(1 - 2^(-11)), to compute tanh(x), we | ||
| // perform the following range reduction: find hi, mid, lo, such that: | ||
| // x = (hi + mid) * log(2) * 0.5 + lo, in which | ||
| // hi is an integer, | ||
| // mid * 2^5 is an integer, | ||
| // -2^(-5) <= lo < 2^(-5). | ||
| // In particular, | ||
| // hi + mid = round(x * log2(e) * 2 * 2^5) * 2^(-5). | ||
| // Then, | ||
| // tanh(x) = sinh(x)/cosh(x) | ||
| // = (e^x - e^(-x)) / (e^x + e^(-x)) | ||
| // = (e^(2x) - 1) / (e^(2x) + 1) | ||
| // = (2^(hi + mid) * e^(2*lo) - 1) / (2^(hi + mid) * e^(2*lo) + 1) | ||
| // = (e^(2*lo) - 2^(-hi - mid)) / (e^(2*lo) + 2^(-hi - mid)) | ||
| // We store 2^(-mid) in the lookup table EXP2_MID_5_BITS, and compute | ||
| // 2^(-hi - mid) by adding -hi to the exponent field of 2^(-mid). | ||
| // e^lo is computed using a degree-3 minimax polynomial generated by Sollya. | ||
|
|
||
| float xf = x; | ||
| float kf = fputil::nearest_integer(xf * (LOG2F_E * 2.0f * 0x1.0p+5f)); | ||
| int x_hi_mid = -static_cast<int>(kf); | ||
| int x_hi = x_hi_mid >> 5; | ||
| int x_mid = x_hi_mid & 0x1f; | ||
| // lo = x - (hi + mid) | ||
| // = round(x * log2(e) * 2 * 2^5) * log(2) * 0.5 * (-2^(-5)) + x | ||
| float lo = fputil::multiply_add(kf, LOGF_2 * 0.5f * -0x1.0p-5f, xf); | ||
|
|
||
| uint32_t exp2_hi_mid_bits = | ||
| EXP2_MID_5_BITS[x_mid] + | ||
| static_cast<uint32_t>(x_hi << fputil::FPBits<float>::FRACTION_LEN); | ||
| // exp2_hi_mid = 2^(-hi - mid) | ||
| float exp2_hi_mid = fputil::FPBits<float>(exp2_hi_mid_bits).get_val(); | ||
| // Degree-3 minimax polynomial generated by Sollya with the following | ||
| // commands: | ||
| // > display = hexadecimal; | ||
| // > P = fpminimax(expm1(2*x)/x, 2, [|SG...|], [-2^-5, 2^-5]); | ||
| // > 1 + x * P; | ||
| float exp_2lo = | ||
| fputil::polyeval(lo, 0x1p+0f, 0x1p+1f, 0x1.001p+1f, 0x1.555ddep+0f); | ||
| return static_cast<float16>((exp_2lo - exp2_hi_mid) / | ||
| (exp_2lo + exp2_hi_mid)); | ||
| } | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| //===-- Implementation header for log10f16 ----------------------*- C++ -*-===// | ||
| // | ||
| // 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_MATH_LOG10F16_H | ||
| #define LLVM_LIBC_SRC_MATH_LOG10F16_H | ||
|
|
||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/properties/types.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| float16 log10f16(float16 x); | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL | ||
|
|
||
| #endif // LLVM_LIBC_SRC_MATH_LOG10F16_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| //===-- Implementation header for log2f16 -----------------------*- C++ -*-===// | ||
| // | ||
| // 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_MATH_LOG2F16_H | ||
| #define LLVM_LIBC_SRC_MATH_LOG2F16_H | ||
|
|
||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/properties/types.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| float16 log2f16(float16 x); | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL | ||
|
|
||
| #endif // LLVM_LIBC_SRC_MATH_LOG2F16_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| //===-- Implementation header for logf16 ------------------------*- C++ -*-===// | ||
| // | ||
| // 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_MATH_LOGF16_H | ||
| #define LLVM_LIBC_SRC_MATH_LOGF16_H | ||
|
|
||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/properties/types.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| float16 logf16(float16 x); | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL | ||
|
|
||
| #endif // LLVM_LIBC_SRC_MATH_LOGF16_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| //===-- Implementation header for sinhf16 -----------------------*- C++ -*-===// | ||
| // | ||
| // 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_MATH_SINHF16_H | ||
| #define LLVM_LIBC_SRC_MATH_SINHF16_H | ||
|
|
||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/properties/types.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| float16 sinhf16(float16 x); | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL | ||
|
|
||
| #endif // LLVM_LIBC_SRC_MATH_SINHF16_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| //===-- Implementation header for sqrtf16 -----------------------*- C++ -*-===// | ||
| // | ||
| // 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_MATH_SQRTF16_H | ||
| #define LLVM_LIBC_SRC_MATH_SQRTF16_H | ||
|
|
||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/properties/types.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| float16 sqrtf16(float16 x); | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL | ||
|
|
||
| #endif // LLVM_LIBC_SRC_MATH_SQRTF16_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| //===-- Implementation header for tanhf16 -----------------------*- C++ -*-===// | ||
| // | ||
| // 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_MATH_TANHF16_H | ||
| #define LLVM_LIBC_SRC_MATH_TANHF16_H | ||
|
|
||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/properties/types.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| float16 tanhf16(float16 x); | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL | ||
|
|
||
| #endif // LLVM_LIBC_SRC_MATH_TANHF16_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| //===-- Exhaustive test for coshf16 ---------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/coshf16.h" | ||
| #include "test/UnitTest/FPMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
| #include "utils/MPFRWrapper/MPFRUtils.h" | ||
|
|
||
| using LlvmLibcCoshf16Test = LIBC_NAMESPACE::testing::FPTest<float16>; | ||
|
|
||
| namespace mpfr = LIBC_NAMESPACE::testing::mpfr; | ||
|
|
||
| // Range: [0, Inf]; | ||
| static constexpr uint16_t POS_START = 0x0000U; | ||
| static constexpr uint16_t POS_STOP = 0x7c00U; | ||
|
|
||
| // Range: [-Inf, 0]; | ||
| static constexpr uint16_t NEG_START = 0x8000U; | ||
| static constexpr uint16_t NEG_STOP = 0xfc00U; | ||
|
|
||
| TEST_F(LlvmLibcCoshf16Test, PositiveRange) { | ||
| for (uint16_t v = POS_START; v <= POS_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Cosh, x, | ||
| LIBC_NAMESPACE::coshf16(x), 0.5); | ||
| } | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcCoshf16Test, NegativeRange) { | ||
| for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Cosh, x, | ||
| LIBC_NAMESPACE::coshf16(x), 0.5); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| //===-- Exhaustive test for exp10m1f16 ------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/exp10m1f16.h" | ||
| #include "test/UnitTest/FPMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
| #include "utils/MPFRWrapper/MPFRUtils.h" | ||
|
|
||
| using LlvmLibcExp10m1f16Test = LIBC_NAMESPACE::testing::FPTest<float16>; | ||
|
|
||
| namespace mpfr = LIBC_NAMESPACE::testing::mpfr; | ||
|
|
||
| // Range: [0, Inf]; | ||
| static constexpr uint16_t POS_START = 0x0000U; | ||
| static constexpr uint16_t POS_STOP = 0x7c00U; | ||
|
|
||
| // Range: [-Inf, 0]; | ||
| static constexpr uint16_t NEG_START = 0x8000U; | ||
| static constexpr uint16_t NEG_STOP = 0xfc00U; | ||
|
|
||
| TEST_F(LlvmLibcExp10m1f16Test, PositiveRange) { | ||
| for (uint16_t v = POS_START; v <= POS_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10m1, x, | ||
| LIBC_NAMESPACE::exp10m1f16(x), 0.5); | ||
| } | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcExp10m1f16Test, NegativeRange) { | ||
| for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10m1, x, | ||
| LIBC_NAMESPACE::exp10m1f16(x), 0.5); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| //===-- Exhaustive test for exp2m1f16 -------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/exp2m1f16.h" | ||
| #include "test/UnitTest/FPMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
| #include "utils/MPFRWrapper/MPFRUtils.h" | ||
|
|
||
| using LlvmLibcExp2m1f16Test = LIBC_NAMESPACE::testing::FPTest<float16>; | ||
|
|
||
| namespace mpfr = LIBC_NAMESPACE::testing::mpfr; | ||
|
|
||
| // Range: [0, Inf]; | ||
| static constexpr uint16_t POS_START = 0x0000U; | ||
| static constexpr uint16_t POS_STOP = 0x7c00U; | ||
|
|
||
| // Range: [-Inf, 0]; | ||
| static constexpr uint16_t NEG_START = 0x8000U; | ||
| static constexpr uint16_t NEG_STOP = 0xfc00U; | ||
|
|
||
| TEST_F(LlvmLibcExp2m1f16Test, PositiveRange) { | ||
| for (uint16_t v = POS_START; v <= POS_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2m1, x, | ||
| LIBC_NAMESPACE::exp2m1f16(x), 0.5); | ||
| } | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcExp2m1f16Test, NegativeRange) { | ||
| for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2m1, x, | ||
| LIBC_NAMESPACE::exp2m1f16(x), 0.5); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| //===-- Exhaustive test for log10f16 --------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/log10f16.h" | ||
| #include "test/UnitTest/FPMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
| #include "utils/MPFRWrapper/MPFRUtils.h" | ||
|
|
||
| using LlvmLibcLog10f16Test = LIBC_NAMESPACE::testing::FPTest<float16>; | ||
|
|
||
| namespace mpfr = LIBC_NAMESPACE::testing::mpfr; | ||
|
|
||
| // Range: [0, Inf]; | ||
| static constexpr uint16_t POS_START = 0x0000U; | ||
| static constexpr uint16_t POS_STOP = 0x7c00U; | ||
|
|
||
| // Range: [-Inf, 0]; | ||
| static constexpr uint16_t NEG_START = 0x8000U; | ||
| static constexpr uint16_t NEG_STOP = 0xfc00U; | ||
|
|
||
| TEST_F(LlvmLibcLog10f16Test, PositiveRange) { | ||
| for (uint16_t v = POS_START; v <= POS_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Log10, x, | ||
| LIBC_NAMESPACE::log10f16(x), 0.5); | ||
| } | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcLog10f16Test, NegativeRange) { | ||
| for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Log10, x, | ||
| LIBC_NAMESPACE::log10f16(x), 0.5); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| //===-- Exhaustive test for log2f16 ---------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/log2f16.h" | ||
| #include "test/UnitTest/FPMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
| #include "utils/MPFRWrapper/MPFRUtils.h" | ||
|
|
||
| using LlvmLibcLog2f16Test = LIBC_NAMESPACE::testing::FPTest<float16>; | ||
|
|
||
| namespace mpfr = LIBC_NAMESPACE::testing::mpfr; | ||
|
|
||
| // Range: [0, Inf]; | ||
| static constexpr uint16_t POS_START = 0x0000U; | ||
| static constexpr uint16_t POS_STOP = 0x7c00U; | ||
|
|
||
| // Range: [-Inf, 0]; | ||
| static constexpr uint16_t NEG_START = 0x8000U; | ||
| static constexpr uint16_t NEG_STOP = 0xfc00U; | ||
|
|
||
| TEST_F(LlvmLibcLog2f16Test, PositiveRange) { | ||
| for (uint16_t v = POS_START; v <= POS_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Log2, x, | ||
| LIBC_NAMESPACE::log2f16(x), 0.5); | ||
| } | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcLog2f16Test, NegativeRange) { | ||
| for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Log2, x, | ||
| LIBC_NAMESPACE::log2f16(x), 0.5); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| //===-- Exhaustive test for logf16 ---------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/logf16.h" | ||
| #include "test/UnitTest/FPMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
| #include "utils/MPFRWrapper/MPFRUtils.h" | ||
|
|
||
| using LlvmLibcLogf16Test = LIBC_NAMESPACE::testing::FPTest<float16>; | ||
|
|
||
| namespace mpfr = LIBC_NAMESPACE::testing::mpfr; | ||
|
|
||
| // Range: [0, Inf]; | ||
| static constexpr uint16_t POS_START = 0x0000U; | ||
| static constexpr uint16_t POS_STOP = 0x7c00U; | ||
|
|
||
| // Range: [-Inf, 0]; | ||
| static constexpr uint16_t NEG_START = 0x8000U; | ||
| static constexpr uint16_t NEG_STOP = 0xfc00U; | ||
|
|
||
| TEST_F(LlvmLibcLogf16Test, PositiveRange) { | ||
| for (uint16_t v = POS_START; v <= POS_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Log, x, | ||
| LIBC_NAMESPACE::logf16(x), 0.5); | ||
| } | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcLogf16Test, NegativeRange) { | ||
| for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Log, x, | ||
| LIBC_NAMESPACE::logf16(x), 0.5); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| //===-- Exhaustive test for sinhf16 ---------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/sinhf16.h" | ||
| #include "test/UnitTest/FPMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
| #include "utils/MPFRWrapper/MPFRUtils.h" | ||
|
|
||
| using LlvmLibcSinhf16Test = LIBC_NAMESPACE::testing::FPTest<float16>; | ||
|
|
||
| namespace mpfr = LIBC_NAMESPACE::testing::mpfr; | ||
|
|
||
| // Range: [0, Inf]; | ||
| static constexpr uint16_t POS_START = 0x0000U; | ||
| static constexpr uint16_t POS_STOP = 0x7c00U; | ||
|
|
||
| // Range: [-Inf, 0]; | ||
| static constexpr uint16_t NEG_START = 0x8000U; | ||
| static constexpr uint16_t NEG_STOP = 0xfc00U; | ||
|
|
||
| TEST_F(LlvmLibcSinhf16Test, PositiveRange) { | ||
| for (uint16_t v = POS_START; v <= POS_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Sinh, x, | ||
| LIBC_NAMESPACE::sinhf16(x), 0.5); | ||
| } | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcSinhf16Test, NegativeRange) { | ||
| for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Sinh, x, | ||
| LIBC_NAMESPACE::sinhf16(x), 0.5); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| //===-- Unittests for coshf16 ---------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "hdr/fenv_macros.h" | ||
| #include "src/errno/libc_errno.h" | ||
| #include "src/math/coshf16.h" | ||
| #include "test/UnitTest/FPMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
|
|
||
| using LlvmLibcCoshf16Test = LIBC_NAMESPACE::testing::FPTest<float16>; | ||
|
|
||
| TEST_F(LlvmLibcCoshf16Test, SpecialNumbers) { | ||
| LIBC_NAMESPACE::libc_errno = 0; | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::coshf16(aNaN)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::coshf16(sNaN), FE_INVALID); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::coshf16(inf)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::coshf16(neg_inf)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(1.0), | ||
| LIBC_NAMESPACE::coshf16(zero)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(1.0), | ||
| LIBC_NAMESPACE::coshf16(neg_zero)); | ||
| EXPECT_MATH_ERRNO(0); | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcCoshf16Test, Overflow) { | ||
| LIBC_NAMESPACE::libc_errno = 0; | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::coshf16(max_normal), | ||
| FE_OVERFLOW | FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::coshf16(neg_max_normal), | ||
| FE_OVERFLOW | FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| // round(acosh(2^16), HP, RU); | ||
| float16 x = static_cast<float16>(0x1.794p+3); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST(inf, LIBC_NAMESPACE::coshf16(x), | ||
| FE_OVERFLOW | FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(inf, LIBC_NAMESPACE::coshf16(x), | ||
| FE_OVERFLOW | FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD( | ||
| max_normal, LIBC_NAMESPACE::coshf16(x), FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO( | ||
| max_normal, LIBC_NAMESPACE::coshf16(x), FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| // round(-acosh(2^16), HP, RD); | ||
| x = static_cast<float16>(-0x1.794p+3); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST(inf, LIBC_NAMESPACE::coshf16(x), | ||
| FE_OVERFLOW | FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(inf, LIBC_NAMESPACE::coshf16(x), | ||
| FE_OVERFLOW | FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD( | ||
| max_normal, LIBC_NAMESPACE::coshf16(x), FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO( | ||
| max_normal, LIBC_NAMESPACE::coshf16(x), FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(0); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| //===-- Unittests for exp10m1f16 ------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "hdr/fenv_macros.h" | ||
| #include "src/errno/libc_errno.h" | ||
| #include "src/math/exp10m1f16.h" | ||
| #include "test/UnitTest/FPMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
|
|
||
| using LlvmLibcExp10m1f16Test = LIBC_NAMESPACE::testing::FPTest<float16>; | ||
|
|
||
| TEST_F(LlvmLibcExp10m1f16Test, SpecialNumbers) { | ||
| LIBC_NAMESPACE::libc_errno = 0; | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::exp10m1f16(aNaN)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::exp10m1f16(sNaN), | ||
| FE_INVALID); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::exp10m1f16(inf)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(-1.0), | ||
| LIBC_NAMESPACE::exp10m1f16(neg_inf)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::exp10m1f16(zero)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, LIBC_NAMESPACE::exp10m1f16(neg_zero)); | ||
| EXPECT_MATH_ERRNO(0); | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcExp10m1f16Test, Overflow) { | ||
| LIBC_NAMESPACE::libc_errno = 0; | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::exp10m1f16(max_normal), | ||
| FE_OVERFLOW | FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| // round(16 * log10(2), HP, RN); | ||
| float16 x = static_cast<float16>(0x1.344p+2); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST( | ||
| inf, LIBC_NAMESPACE::exp10m1f16(x), FE_OVERFLOW | FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD( | ||
| inf, LIBC_NAMESPACE::exp10m1f16(x), FE_OVERFLOW | FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD( | ||
| max_normal, LIBC_NAMESPACE::exp10m1f16(x), FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO( | ||
| max_normal, LIBC_NAMESPACE::exp10m1f16(x), FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(0); | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcExp10m1f16Test, ResultNearNegOne) { | ||
| LIBC_NAMESPACE::libc_errno = 0; | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(static_cast<float16>(-1.0), | ||
| LIBC_NAMESPACE::exp10m1f16(neg_max_normal), | ||
| FE_INEXACT); | ||
|
|
||
| // round(-11 * log10(2), HP, RD); | ||
| float16 x = static_cast<float16>(-0x1.a8p+1); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST( | ||
| static_cast<float16>(-0x1.ffcp-1), LIBC_NAMESPACE::exp10m1f16(x), | ||
| FE_INEXACT); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(static_cast<float16>(-0x1.ffcp-1), | ||
| LIBC_NAMESPACE::exp10m1f16(x), | ||
| FE_INEXACT); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD( | ||
| static_cast<float16>(-1.0), LIBC_NAMESPACE::exp10m1f16(x), FE_INEXACT); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO( | ||
| static_cast<float16>(-0x1.ffcp-1), LIBC_NAMESPACE::exp10m1f16(x), | ||
| FE_INEXACT); | ||
|
|
||
| // Next float16 value below -0x1.ce4p+1. | ||
| x = static_cast<float16>(-0x1.ce8p+1); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST( | ||
| static_cast<float16>(-1.0), LIBC_NAMESPACE::exp10m1f16(x), FE_INEXACT); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(static_cast<float16>(-0x1.ffcp-1), | ||
| LIBC_NAMESPACE::exp10m1f16(x), | ||
| FE_INEXACT); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD( | ||
| static_cast<float16>(-1.0), LIBC_NAMESPACE::exp10m1f16(x), FE_INEXACT); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO( | ||
| static_cast<float16>(-0x1.ffcp-1), LIBC_NAMESPACE::exp10m1f16(x), | ||
| FE_INEXACT); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| //===-- Unittests for exp2m1f16 -------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "hdr/errno_macros.h" | ||
| #include "hdr/fenv_macros.h" | ||
| #include "src/errno/libc_errno.h" | ||
| #include "src/math/exp2m1f16.h" | ||
| #include "test/UnitTest/FPMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
|
|
||
| using LlvmLibcExp2m1f16Test = LIBC_NAMESPACE::testing::FPTest<float16>; | ||
|
|
||
| TEST_F(LlvmLibcExp2m1f16Test, SpecialNumbers) { | ||
| LIBC_NAMESPACE::libc_errno = 0; | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::exp2m1f16(aNaN)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::exp2m1f16(sNaN), | ||
| FE_INVALID); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::exp2m1f16(inf)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(-1.0), | ||
| LIBC_NAMESPACE::exp2m1f16(neg_inf)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::exp2m1f16(zero)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, LIBC_NAMESPACE::exp2m1f16(neg_zero)); | ||
| EXPECT_MATH_ERRNO(0); | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcExp2m1f16Test, Overflow) { | ||
| LIBC_NAMESPACE::libc_errno = 0; | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::exp2m1f16(max_normal), | ||
| FE_OVERFLOW | FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| float16 x = static_cast<float16>(16.0); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST( | ||
| inf, LIBC_NAMESPACE::exp2m1f16(x), FE_OVERFLOW | FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(inf, LIBC_NAMESPACE::exp2m1f16(x), | ||
| FE_OVERFLOW | FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD( | ||
| max_normal, LIBC_NAMESPACE::exp2m1f16(x), FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO( | ||
| max_normal, LIBC_NAMESPACE::exp2m1f16(x), FE_INEXACT); | ||
| EXPECT_MATH_ERRNO(0); | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcExp2m1f16Test, ResultNearNegOne) { | ||
| LIBC_NAMESPACE::libc_errno = 0; | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(static_cast<float16>(-1.0), | ||
| LIBC_NAMESPACE::exp2m1f16(neg_max_normal), | ||
| FE_INEXACT); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING( | ||
| static_cast<float16>(-0x1.ffcp-1), | ||
| LIBC_NAMESPACE::exp2m1f16(static_cast<float16>(-11))); | ||
|
|
||
| float16 x = static_cast<float16>(-12); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST( | ||
| static_cast<float16>(-1.0), LIBC_NAMESPACE::exp2m1f16(x), FE_INEXACT); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(static_cast<float16>(-0x1.ffcp-1), | ||
| LIBC_NAMESPACE::exp2m1f16(x), | ||
| FE_INEXACT); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD( | ||
| static_cast<float16>(-1.0), LIBC_NAMESPACE::exp2m1f16(x), FE_INEXACT); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO( | ||
| static_cast<float16>(-0x1.ffcp-1), LIBC_NAMESPACE::exp2m1f16(x), | ||
| FE_INEXACT); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| //===-- Unittests for log10f16 --------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "hdr/fenv_macros.h" | ||
| #include "src/errno/libc_errno.h" | ||
| #include "src/math/log10f16.h" | ||
| #include "test/UnitTest/FPMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
|
|
||
| using LlvmLibcLog10f16Test = LIBC_NAMESPACE::testing::FPTest<float16>; | ||
|
|
||
| TEST_F(LlvmLibcLog10f16Test, SpecialNumbers) { | ||
| LIBC_NAMESPACE::libc_errno = 0; | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::log10f16(aNaN)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::log10f16(sNaN), FE_INVALID); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::log10f16(inf)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::log10f16(neg_inf)); | ||
| EXPECT_MATH_ERRNO(EDOM); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ALL_ROUNDING( | ||
| neg_inf, LIBC_NAMESPACE::log10f16(zero), FE_DIVBYZERO); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION_ALL_ROUNDING( | ||
| neg_inf, LIBC_NAMESPACE::log10f16(neg_zero), FE_DIVBYZERO); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING( | ||
| zero, LIBC_NAMESPACE::log10f16(static_cast<float16>(1.0))); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING( | ||
| aNaN, LIBC_NAMESPACE::log10f16(static_cast<float16>(-1.0))); | ||
| EXPECT_MATH_ERRNO(EDOM); | ||
| } |