//===-- Unittests for the DyadicFloat class -------------------------------===// // // 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/__support/FPUtil/dyadic_float.h" #include "src/__support/big_int.h" #include "src/__support/macros/properties/types.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" #include "utils/MPFRWrapper/MPFRUtils.h" using Float128 = LIBC_NAMESPACE::fputil::DyadicFloat<128>; using Float192 = LIBC_NAMESPACE::fputil::DyadicFloat<192>; using Float256 = LIBC_NAMESPACE::fputil::DyadicFloat<256>; using LIBC_NAMESPACE::Sign; TEST(LlvmLibcDyadicFloatTest, BasicConversions) { Float128 x(Sign::POS, /*exponent*/ 0, /*mantissa*/ Float128::MantissaType(1)); ASSERT_FP_EQ(1.0f, float(x)); ASSERT_FP_EQ(1.0, double(x)); Float128 y(0x1.0p-53); ASSERT_FP_EQ(0x1.0p-53f, float(y)); ASSERT_FP_EQ(0x1.0p-53, double(y)); Float128 z = quick_add(x, y); EXPECT_FP_EQ_ALL_ROUNDING(float(x) + float(y), float(z)); EXPECT_FP_EQ_ALL_ROUNDING(double(x) + double(y), double(z)); } TEST(LlvmLibcDyadicFloatTest, QuickAdd) { Float192 x(Sign::POS, /*exponent*/ 0, /*mantissa*/ Float192::MantissaType(0x123456)); ASSERT_FP_EQ(0x1.23456p20, double(x)); Float192 y(0x1.abcdefp-20); ASSERT_FP_EQ(0x1.abcdefp-20, double(y)); Float192 z = quick_add(x, y); EXPECT_FP_EQ_ALL_ROUNDING(double(x) + double(y), double(z)); } TEST(LlvmLibcDyadicFloatTest, QuickMul) { Float256 x(Sign::POS, /*exponent*/ 0, /*mantissa*/ Float256::MantissaType(0x123456)); ASSERT_FP_EQ(0x1.23456p20, double(x)); Float256 y(0x1.abcdefp-25); ASSERT_FP_EQ(0x1.abcdefp-25, double(y)); Float256 z = quick_mul(x, y); EXPECT_FP_EQ_ALL_ROUNDING(double(x) * double(y), double(z)); } #define TEST_EDGE_RANGES(Name, Type) \ TEST(LlvmLibcDyadicFloatTest, EdgeRanges##Name) { \ using Bits = LIBC_NAMESPACE::fputil::FPBits; \ using DFType = LIBC_NAMESPACE::fputil::DyadicFloat; \ Type max_normal = Bits::max_normal().get_val(); \ Type min_normal = Bits::min_normal().get_val(); \ Type min_subnormal = Bits::min_subnormal().get_val(); \ Type two(2); \ \ DFType x(min_normal); \ EXPECT_FP_EQ_ALL_ROUNDING(min_normal, static_cast(x)); \ --x.exponent; \ EXPECT_FP_EQ(min_normal / two, static_cast(x)); \ \ DFType y(two *min_normal - min_subnormal); \ --y.exponent; \ EXPECT_FP_EQ(min_normal, static_cast(y)); \ \ DFType z(min_subnormal); \ EXPECT_FP_EQ_ALL_ROUNDING(min_subnormal, static_cast(z)); \ --z.exponent; \ EXPECT_FP_EQ(Bits::zero().get_val(), static_cast(z)); \ \ DFType t(max_normal); \ EXPECT_FP_EQ_ALL_ROUNDING(max_normal, static_cast(t)); \ ++t.exponent; \ EXPECT_FP_EQ(Bits::inf().get_val(), static_cast(t)); \ } \ static_assert(true, "Require semicolon.") TEST_EDGE_RANGES(Float, float); TEST_EDGE_RANGES(Double, double); TEST_EDGE_RANGES(LongDouble, long double); #ifdef LIBC_TYPES_HAS_FLOAT16 TEST_EDGE_RANGES(Float16, float16); #endif