| //===-- Unittests for lgammaf ---------------------------------------------===// | |
| // | |
| // 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/stdint_proxy.h" | |
| #include "src/__support/FPUtil/FPBits.h" | |
| #include "src/__support/libc_errno.h" | |
| #include "src/math/lgammaf.h" | |
| #include "test/UnitTest/FPMatcher.h" | |
| #include "test/UnitTest/Test.h" | |
| #include "utils/MPFRWrapper/MPFRUtils.h" | |
| using LlvmLibcLgammafTest = LIBC_NAMESPACE::testing::FPTest<float>; | |
| namespace mpfr = LIBC_NAMESPACE::testing::mpfr; | |
| // Hard-to-round cases collected from prior exhaustive tests. | |
| // Each is a midpoint-case where small precision drift in the implementation | |
| // tips the double to float rounding direction. | |
| TEST_F(LlvmLibcLgammafTest, HardCases) { | |
| static constexpr uint32_t INPUTS[] = { | |
| 0x77ac5740u, // 0x1.58ace8p+112 (huge positive, Stirling path) | |
| 0x87acf970u, // -0x1.f59f2ep-16 (small negative, reflection path) | |
| 0xc0afda0bu, // -0x1.5fb416p+1 (negative middle, reflection through M3) | |
| 0x3fc0737cu, // 0x1.80e6f8p+0 (medium near lgamma minimum) | |
| 0x3fc07be9u, // 0x1.80f7d2p+0 (same) | |
| 0x3fd0b2bfu, // 0x1.a1657ep+0 (same) | |
| 0xb3000824u, // -0x1.001048p-25 (tiny negative) | |
| 0x30f00a14u, // 0x1.e01428p-30 (tiny positive) | |
| 0x00800000u, // 0x1p-126 (min normal positive) | |
| 0x80800000u, // -0x1p-126 (min normal negative) | |
| 0x3f800000u, // 0x1p+0 (lgamma(1) = 0 exactly) | |
| 0x40000000u, // 0x1p+1 (lgamma(2) = 0 exactly) | |
| }; | |
| for (uint32_t v : INPUTS) { | |
| float x = FPBits(v).get_val(); | |
| libc_errno = 0; | |
| float result = LIBC_NAMESPACE::lgammaf(x); | |
| if (FPBits(result).is_nan() || FPBits(result).is_inf() || libc_errno != 0) | |
| continue; | |
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Lgamma, x, | |
| LIBC_NAMESPACE::lgammaf(x), 0.5); | |
| } | |
| } | |
| TEST_F(LlvmLibcLgammafTest, PositiveRange) { | |
| constexpr uint32_t COUNT = 1'231; | |
| // [min normal, max_normal]. | |
| constexpr uint32_t POS_START = 0x0080'0000U; | |
| constexpr uint32_t POS_STOP = 0x7f7f'ffffU; | |
| constexpr uint32_t STEP = (POS_STOP - POS_START) / COUNT; | |
| for (uint32_t i = 0, v = POS_START; i <= COUNT; ++i, v += STEP) { | |
| float x = FPBits(v).get_val(); | |
| libc_errno = 0; | |
| float result = LIBC_NAMESPACE::lgammaf(x); | |
| if (FPBits(result).is_nan() || FPBits(result).is_inf() || libc_errno != 0) | |
| continue; | |
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Lgamma, x, | |
| LIBC_NAMESPACE::lgammaf(x), 0.5); | |
| } | |
| } | |
| TEST_F(LlvmLibcLgammafTest, NegativeRange) { | |
| constexpr uint32_t COUNT = 1'231; | |
| //-max_normal, -min normal]. | |
| constexpr uint32_t NEG_START = 0x8080'0000U; | |
| constexpr uint32_t NEG_STOP = 0xff7f'ffffU; | |
| constexpr uint32_t STEP = (NEG_STOP - NEG_START) / COUNT; | |
| for (uint32_t i = 0, v = NEG_START; i <= COUNT; ++i, v += STEP) { | |
| float x = FPBits(v).get_val(); | |
| if (FPBits(v).is_nan() || FPBits(v).is_inf()) | |
| continue; | |
| libc_errno = 0; | |
| float result = LIBC_NAMESPACE::lgammaf(x); | |
| if (FPBits(result).is_nan() || FPBits(result).is_inf() || libc_errno != 0) | |
| continue; | |
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Lgamma, x, | |
| LIBC_NAMESPACE::lgammaf(x), 0.5); | |
| } | |
| } | |
| TEST_F(LlvmLibcLgammafTest, SmallRange) { | |
| constexpr float LO = -4.0f; | |
| constexpr float HI = 4.0f; | |
| constexpr uint32_t COUNT = 1'231; | |
| for (uint32_t i = 0; i <= COUNT; ++i) { | |
| float x = | |
| LO + (HI - LO) * static_cast<float>(i) / static_cast<float>(COUNT); | |
| libc_errno = 0; | |
| float result = LIBC_NAMESPACE::lgammaf(x); | |
| if (FPBits(result).is_nan() || FPBits(result).is_inf() || libc_errno != 0) | |
| continue; | |
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Lgamma, x, | |
| LIBC_NAMESPACE::lgammaf(x), 0.5); | |
| } | |
| } |