diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -155,12 +155,14 @@ "copysignl", "ceil", "ceilf", + "ceill", "cosf", "fabs", "fabsf", "fabsl", "floor", "floorf", + "floorl", "frexp", "frexpf", "frexpl", @@ -174,6 +176,7 @@ "exp2f", "round", "roundf", + "roundl", "sincosf", "sinf", "trunc", diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -51,6 +51,7 @@ libc.src.math.copysignl libc.src.math.ceil libc.src.math.ceilf + libc.src.math.ceill libc.src.math.cosf libc.src.math.expf libc.src.math.exp2f @@ -59,6 +60,7 @@ libc.src.math.fabsl libc.src.math.floor libc.src.math.floorf + libc.src.math.floorl libc.src.math.frexp libc.src.math.frexpf libc.src.math.frexpl @@ -70,6 +72,7 @@ libc.src.math.modfl libc.src.math.round libc.src.math.roundf + libc.src.math.roundl libc.src.math.sincosf libc.src.math.sinf libc.src.math.trunc diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -195,6 +195,7 @@ FunctionSpec<"ceil", RetValSpec, [ArgSpec]>, FunctionSpec<"ceilf", RetValSpec, [ArgSpec]>, + FunctionSpec<"ceill", RetValSpec, [ArgSpec]>, FunctionSpec<"fabs", RetValSpec, [ArgSpec]>, FunctionSpec<"fabsf", RetValSpec, [ArgSpec]>, @@ -202,6 +203,7 @@ FunctionSpec<"floor", RetValSpec, [ArgSpec]>, FunctionSpec<"floorf", RetValSpec, [ArgSpec]>, + FunctionSpec<"floorl", RetValSpec, [ArgSpec]>, FunctionSpec<"frexp", RetValSpec, [ArgSpec, ArgSpec]>, FunctionSpec<"frexpf", RetValSpec, [ArgSpec, ArgSpec]>, @@ -223,6 +225,7 @@ FunctionSpec<"round", RetValSpec, [ArgSpec]>, FunctionSpec<"roundf", RetValSpec, [ArgSpec]>, + FunctionSpec<"roundl", RetValSpec, [ArgSpec]>, FunctionSpec<"trunc", RetValSpec, [ArgSpec]>, FunctionSpec<"truncf", RetValSpec, [ArgSpec]>, diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -152,6 +152,18 @@ -O2 ) +add_entrypoint_object( + ceill + SRCS + ceill.cpp + HDRS + ceill.h + DEPENDS + libc.utils.FPUtil.fputil + COMPILE_OPTIONS + -O2 +) + add_entrypoint_object( floor SRCS @@ -176,6 +188,18 @@ -O2 ) +add_entrypoint_object( + floorl + SRCS + floorl.cpp + HDRS + floorl.h + DEPENDS + libc.utils.FPUtil.fputil + COMPILE_OPTIONS + -O2 +) + add_entrypoint_object( round SRCS @@ -184,6 +208,8 @@ round.h DEPENDS libc.utils.FPUtil.fputil + COMPILE_OPTIONS + -O2 ) add_entrypoint_object( @@ -194,6 +220,20 @@ roundf.h DEPENDS libc.utils.FPUtil.fputil + COMPILE_OPTIONS + -O2 +) + +add_entrypoint_object( + roundl + SRCS + roundl.cpp + HDRS + roundl.h + DEPENDS + libc.utils.FPUtil.fputil + COMPILE_OPTIONS + -O2 ) add_object_library( diff --git a/libc/src/math/ceill.h b/libc/src/math/ceill.h new file mode 100644 --- /dev/null +++ b/libc/src/math/ceill.h @@ -0,0 +1,18 @@ +//===-- Implementation header for ceill -------------------------*- 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_CEILL_H +#define LLVM_LIBC_SRC_MATH_CEILL_H + +namespace __llvm_libc { + +long double ceill(long double x); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_CEILL_H diff --git a/libc/src/math/ceill.cpp b/libc/src/math/ceill.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/ceill.cpp @@ -0,0 +1,18 @@ +//===-- Implementation of ceill 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/__support/common.h" +#include "utils/FPUtil/NearestIntegerOperations.h" + +namespace __llvm_libc { + +long double LLVM_LIBC_ENTRYPOINT(ceill)(long double x) { + return fputil::ceil(x); +} + +} // namespace __llvm_libc diff --git a/libc/src/math/floorl.h b/libc/src/math/floorl.h new file mode 100644 --- /dev/null +++ b/libc/src/math/floorl.h @@ -0,0 +1,18 @@ +//===-- Implementation header for floorl ------------------------*- 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_FLOORL_H +#define LLVM_LIBC_SRC_MATH_FLOORL_H + +namespace __llvm_libc { + +long double floorl(long double x); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_FLOORL_H diff --git a/libc/src/math/floorl.cpp b/libc/src/math/floorl.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/floorl.cpp @@ -0,0 +1,18 @@ +//===-- Implementation of floorl 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/__support/common.h" +#include "utils/FPUtil/NearestIntegerOperations.h" + +namespace __llvm_libc { + +long double LLVM_LIBC_ENTRYPOINT(floorl)(long double x) { + return fputil::floor(x); +} + +} // namespace __llvm_libc diff --git a/libc/src/math/roundl.h b/libc/src/math/roundl.h new file mode 100644 --- /dev/null +++ b/libc/src/math/roundl.h @@ -0,0 +1,18 @@ +//===-- Implementation header for roundl ------------------------*- 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_ROUNDL_H +#define LLVM_LIBC_SRC_MATH_ROUNDL_H + +namespace __llvm_libc { + +long double roundl(long double x); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_ROUNDL_H diff --git a/libc/src/math/roundl.cpp b/libc/src/math/roundl.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/roundl.cpp @@ -0,0 +1,18 @@ +//===-- Implementation of roundl 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/__support/common.h" +#include "utils/FPUtil/NearestIntegerOperations.h" + +namespace __llvm_libc { + +long double LLVM_LIBC_ENTRYPOINT(roundl)(long double x) { + return fputil::round(x); +} + +} // namespace __llvm_libc diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -175,6 +175,19 @@ libc.utils.FPUtil.fputil ) +add_math_unittest( + ceill_test + NEED_MPFR + SUITE + libc_math_unittests + SRCS + ceill_test.cpp + DEPENDS + libc.include.math + libc.src.math.ceill + libc.utils.FPUtil.fputil +) + add_math_unittest( floor_test NEED_MPFR @@ -201,6 +214,19 @@ libc.utils.FPUtil.fputil ) +add_math_unittest( + floorl_test + NEED_MPFR + SUITE + libc_math_unittests + SRCS + floorl_test.cpp + DEPENDS + libc.include.math + libc.src.math.floorl + libc.utils.FPUtil.fputil +) + add_math_unittest( round_test NEED_MPFR @@ -227,6 +253,19 @@ libc.utils.FPUtil.fputil ) +add_math_unittest( + roundl_test + NEED_MPFR + SUITE + libc_math_unittests + SRCS + roundl_test.cpp + DEPENDS + libc.include.math + libc.src.math.roundl + libc.utils.FPUtil.fputil +) + add_math_unittest( expf_test NEED_MPFR diff --git a/libc/test/src/math/ceill_test.cpp b/libc/test/src/math/ceill_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/ceill_test.cpp @@ -0,0 +1,72 @@ +//===-- Unittests for ceill -----------------------------------------------===// +// +// 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 "include/math.h" +#include "src/math/ceill.h" +#include "utils/FPUtil/FPBits.h" +#include "utils/MPFRWrapper/MPFRUtils.h" +#include "utils/UnitTest/Test.h" + +using FPBits = __llvm_libc::fputil::FPBits; + +namespace mpfr = __llvm_libc::testing::mpfr; + +// Zero tolerance; As in, exact match with MPFR result. +static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::doublePrecision, 0, + 0}; +TEST(CeillTest, SpecialNumbers) { + ASSERT_TRUE(FPBits::zero() == __llvm_libc::ceill(FPBits::zero())); + ASSERT_TRUE(FPBits::negZero() == __llvm_libc::ceill(FPBits::negZero())); + + ASSERT_TRUE(FPBits::inf() == __llvm_libc::ceill(FPBits::inf())); + ASSERT_TRUE(FPBits::negInf() == __llvm_libc::ceill(FPBits::negInf())); + + long double nan = FPBits::buildNaN(1); + ASSERT_TRUE(isnan(nan) != 0); + ASSERT_TRUE(isnan(__llvm_libc::ceill(nan)) != 0); +} + +TEST(CeillTest, RoundedNumbers) { + ASSERT_TRUE(FPBits(1.0l) == __llvm_libc::ceill(1.0l)); + ASSERT_TRUE(FPBits(-1.0l) == __llvm_libc::ceill(-1.0l)); + ASSERT_TRUE(FPBits(10.0l) == __llvm_libc::ceill(10.0l)); + ASSERT_TRUE(FPBits(-10.0l) == __llvm_libc::ceill(-10.0l)); + ASSERT_TRUE(FPBits(1234.0l) == __llvm_libc::ceill(1234.0l)); + ASSERT_TRUE(FPBits(-1234.0l) == __llvm_libc::ceill(-1234.0l)); +} + +TEST(CeillTest, Fractions) { + ASSERT_TRUE(FPBits(2.0l) == __llvm_libc::ceill(1.3l)); + ASSERT_TRUE(FPBits(-1.0l) == __llvm_libc::ceill(-1.3l)); + ASSERT_TRUE(FPBits(2.0l) == __llvm_libc::ceill(1.5l)); + ASSERT_TRUE(FPBits(-1.0l) == __llvm_libc::ceill(-1.5l)); + ASSERT_TRUE(FPBits(2.0l) == __llvm_libc::ceill(1.75l)); + ASSERT_TRUE(FPBits(-1.0l) == __llvm_libc::ceill(-1.75l)); + ASSERT_TRUE(FPBits(11.0l) == __llvm_libc::ceill(10.32l)); + ASSERT_TRUE(FPBits(-10.0l) == __llvm_libc::ceill(-10.32l)); + ASSERT_TRUE(FPBits(11.0l) == __llvm_libc::ceill(10.65l)); + ASSERT_TRUE(FPBits(-10.0l) == __llvm_libc::ceill(-10.65l)); + ASSERT_TRUE(FPBits(1235.0l) == __llvm_libc::ceill(1234.18l)); + ASSERT_TRUE(FPBits(-1234.0l) == __llvm_libc::ceill(-1234.18l)); + ASSERT_TRUE(FPBits(1235.0l) == __llvm_libc::ceill(1234.96l)); + ASSERT_TRUE(FPBits(-1234.0l) == __llvm_libc::ceill(-1234.96l)); +} + +TEST(CeillTest, InLongDoubleRange) { + using UIntType = FPBits::UIntType; + constexpr UIntType count = 10000000; + constexpr UIntType step = UIntType(-1) / count; + for (UIntType i = 0, v = 0; i <= count; ++i, v += step) { + long double x = FPBits(v); + if (isnan(x) || isinf(x)) + continue; + + ASSERT_MPFR_MATCH(mpfr::Operation::Ceil, x, __llvm_libc::ceill(x), + tolerance); + } +} diff --git a/libc/test/src/math/floorl_test.cpp b/libc/test/src/math/floorl_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/floorl_test.cpp @@ -0,0 +1,72 @@ +//===-- Unittests for floorl ----------------------------------------------===// +// +// 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 "include/math.h" +#include "src/math/floorl.h" +#include "utils/FPUtil/FPBits.h" +#include "utils/MPFRWrapper/MPFRUtils.h" +#include "utils/UnitTest/Test.h" + +using FPBits = __llvm_libc::fputil::FPBits; + +namespace mpfr = __llvm_libc::testing::mpfr; + +// Zero tolerance; As in, exact match with MPFR result. +static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::doublePrecision, 0, + 0}; +TEST(FloorlTest, SpecialNumbers) { + ASSERT_TRUE(FPBits::zero() == __llvm_libc::floorl(FPBits::zero())); + ASSERT_TRUE(FPBits::negZero() == __llvm_libc::floorl(FPBits::negZero())); + + ASSERT_TRUE(FPBits::inf() == __llvm_libc::floorl(FPBits::inf())); + ASSERT_TRUE(FPBits::negInf() == __llvm_libc::floorl(FPBits::negInf())); + + long double nan = FPBits::buildNaN(1); + ASSERT_TRUE(isnan(nan) != 0); + ASSERT_TRUE(isnan(__llvm_libc::floorl(nan)) != 0); +} + +TEST(FloorlTest, RoundedNumbers) { + ASSERT_TRUE(FPBits(1.0l) == __llvm_libc::floorl(1.0l)); + ASSERT_TRUE(FPBits(-1.0l) == __llvm_libc::floorl(-1.0l)); + ASSERT_TRUE(FPBits(10.0l) == __llvm_libc::floorl(10.0l)); + ASSERT_TRUE(FPBits(-10.0l) == __llvm_libc::floorl(-10.0l)); + ASSERT_TRUE(FPBits(1234.0l) == __llvm_libc::floorl(1234.0l)); + ASSERT_TRUE(FPBits(-1234.0l) == __llvm_libc::floorl(-1234.0l)); +} + +TEST(FloorlTest, Fractions) { + ASSERT_TRUE(FPBits(1.0l) == __llvm_libc::floorl(1.3l)); + ASSERT_TRUE(FPBits(-2.0l) == __llvm_libc::floorl(-1.3l)); + ASSERT_TRUE(FPBits(1.0l) == __llvm_libc::floorl(1.5l)); + ASSERT_TRUE(FPBits(-2.0l) == __llvm_libc::floorl(-1.5l)); + ASSERT_TRUE(FPBits(1.0l) == __llvm_libc::floorl(1.75l)); + ASSERT_TRUE(FPBits(-2.0l) == __llvm_libc::floorl(-1.75l)); + ASSERT_TRUE(FPBits(10.0l) == __llvm_libc::floorl(10.32l)); + ASSERT_TRUE(FPBits(-11.0l) == __llvm_libc::floorl(-10.32l)); + ASSERT_TRUE(FPBits(10.0l) == __llvm_libc::floorl(10.65l)); + ASSERT_TRUE(FPBits(-11.0l) == __llvm_libc::floorl(-10.65l)); + ASSERT_TRUE(FPBits(1234.0l) == __llvm_libc::floorl(1234.18l)); + ASSERT_TRUE(FPBits(-1235.0l) == __llvm_libc::floorl(-1234.18l)); + ASSERT_TRUE(FPBits(1234.0l) == __llvm_libc::floorl(1234.96l)); + ASSERT_TRUE(FPBits(-1235.0l) == __llvm_libc::floorl(-1234.96l)); +} + +TEST(FloorlTest, InLongDoubleRange) { + using UIntType = FPBits::UIntType; + constexpr UIntType count = 10000000; + constexpr UIntType step = UIntType(-1) / count; + for (UIntType i = 0, v = 0; i <= count; ++i, v += step) { + long double x = FPBits(v); + if (isnan(x) || isinf(x)) + continue; + + ASSERT_MPFR_MATCH(mpfr::Operation::Floor, x, __llvm_libc::floorl(x), + tolerance); + } +} diff --git a/libc/test/src/math/roundl_test.cpp b/libc/test/src/math/roundl_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/roundl_test.cpp @@ -0,0 +1,72 @@ +//===-- Unittests for roundl ----------------------------------------------===// +// +// 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 "include/math.h" +#include "src/math/roundl.h" +#include "utils/FPUtil/FPBits.h" +#include "utils/MPFRWrapper/MPFRUtils.h" +#include "utils/UnitTest/Test.h" + +using FPBits = __llvm_libc::fputil::FPBits; + +namespace mpfr = __llvm_libc::testing::mpfr; + +// Zero tolerance; As in, exact match with MPFR result. +static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::floatPrecision, 0, + 0}; +TEST(RoundlTest, SpecialNumbers) { + ASSERT_TRUE(FPBits::zero() == __llvm_libc::roundl(FPBits::zero())); + ASSERT_TRUE(FPBits::negZero() == __llvm_libc::roundl(FPBits::negZero())); + + ASSERT_TRUE(FPBits::inf() == __llvm_libc::roundl(FPBits::inf())); + ASSERT_TRUE(FPBits::negInf() == __llvm_libc::roundl(FPBits::negInf())); + + long double nan = FPBits::buildNaN(1); + ASSERT_TRUE(isnan(nan) != 0); + ASSERT_TRUE(isnan(__llvm_libc::roundl(nan)) != 0); +} + +TEST(RoundlTest, RoundedNumbers) { + ASSERT_TRUE(FPBits(1.0l) == __llvm_libc::roundl(1.0l)); + ASSERT_TRUE(FPBits(-1.0l) == __llvm_libc::roundl(-1.0l)); + ASSERT_TRUE(FPBits(10.0l) == __llvm_libc::roundl(10.0l)); + ASSERT_TRUE(FPBits(-10.0l) == __llvm_libc::roundl(-10.0l)); + ASSERT_TRUE(FPBits(1234.0l) == __llvm_libc::roundl(1234.0l)); + ASSERT_TRUE(FPBits(-1234.0l) == __llvm_libc::roundl(-1234.0l)); +} + +TEST(RoundlTest, Fractions) { + ASSERT_TRUE(FPBits(1.0l) == __llvm_libc::roundl(1.3l)); + ASSERT_TRUE(FPBits(-1.0l) == __llvm_libc::roundl(-1.3l)); + ASSERT_TRUE(FPBits(2.0l) == __llvm_libc::roundl(1.5l)); + ASSERT_TRUE(FPBits(-2.0l) == __llvm_libc::roundl(-1.5l)); + ASSERT_TRUE(FPBits(2.0l) == __llvm_libc::roundl(1.75l)); + ASSERT_TRUE(FPBits(-2.0l) == __llvm_libc::roundl(-1.75l)); + ASSERT_TRUE(FPBits(10.0l) == __llvm_libc::roundl(10.32l)); + ASSERT_TRUE(FPBits(-10.0l) == __llvm_libc::roundl(-10.32l)); + ASSERT_TRUE(FPBits(11.0l) == __llvm_libc::roundl(10.65l)); + ASSERT_TRUE(FPBits(-11.0l) == __llvm_libc::roundl(-10.65l)); + ASSERT_TRUE(FPBits(1234.0l) == __llvm_libc::roundl(1234.38l)); + ASSERT_TRUE(FPBits(-1234.0l) == __llvm_libc::roundl(-1234.38l)); + ASSERT_TRUE(FPBits(1235.0l) == __llvm_libc::roundl(1234.96l)); + ASSERT_TRUE(FPBits(-1235.0l) == __llvm_libc::roundl(-1234.96l)); +} + +TEST(RoundlTest, InLongDoubleRange) { + using UIntType = FPBits::UIntType; + constexpr UIntType count = 10000000; + constexpr UIntType step = UIntType(-1) / count; + for (UIntType i = 0, v = 0; i <= count; ++i, v += step) { + long double x = FPBits(v); + if (isnan(x) || isinf(x)) + continue; + + ASSERT_MPFR_MATCH(mpfr::Operation::Round, x, __llvm_libc::roundl(x), + tolerance); + } +} diff --git a/libc/utils/FPUtil/NearestIntegerOperations.h b/libc/utils/FPUtil/NearestIntegerOperations.h --- a/libc/utils/FPUtil/NearestIntegerOperations.h +++ b/libc/utils/FPUtil/NearestIntegerOperations.h @@ -9,10 +9,7 @@ #ifndef LLVM_LIBC_UTILS_FPUTIL_NEAREST_INTEGER_OPERATIONS_H #define LLVM_LIBC_UTILS_FPUTIL_NEAREST_INTEGER_OPERATIONS_H -#include "ClassificationFunctions.h" #include "FPBits.h" -#include "FloatOperations.h" -#include "FloatProperties.h" #include "utils/CPP/TypeTraits.h" @@ -54,21 +51,18 @@ template ::Value, int> = 0> static inline T ceil(T x) { - using Properties = FloatProperties; - using BitsType = typename FloatProperties::BitsType; - - BitsType bits = valueAsBits(x); + FPBits bits(x); // If x is infinity NaN or zero, return it. - if (bitsAreInfOrNaN(bits) || bitsAreZero(bits)) + if (bits.isInfOrNaN() || bits.isZero()) return x; - bool isNeg = bits & Properties::signMask; - int exponent = getExponentFromBits(bits); + bool isNeg = bits.sign; + int exponent = bits.getExponent(); // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. - if (exponent >= static_cast(Properties::mantissaWidth)) + if (exponent >= static_cast(MantissaWidth::value)) return x; if (exponent <= -1) { @@ -78,14 +72,14 @@ return T(1.0); } - uint32_t trimSize = Properties::mantissaWidth - exponent; + uint32_t trimSize = MantissaWidth::value - exponent; + bits.mantissa = (bits.mantissa >> trimSize) << trimSize; + T truncValue = T(bits); + // If x is already an integer, return it. - if ((bits << (Properties::bitWidth - trimSize)) == 0) + if (truncValue == x) return x; - BitsType truncBits = (bits >> trimSize) << trimSize; - T truncValue = valueFromBits(truncBits); - // If x is negative, the ceil operation is equivalent to the trunc operation. if (isNeg) return truncValue; @@ -96,8 +90,8 @@ template ::Value, int> = 0> static inline T floor(T x) { - auto bits = valueAsBits(x); - if (FloatProperties::signMask & bits) { + FPBits bits(x); + if (bits.sign) { return -ceil(-x); } else { return trunc(x); @@ -107,21 +101,19 @@ template ::Value, int> = 0> static inline T round(T x) { - using Properties = FloatProperties; - using BitsType = typename FloatProperties::BitsType; - - BitsType bits = valueAsBits(x); + using UIntType = typename FPBits::UIntType; + FPBits bits(x); - // If x is infinity, NaN or zero, return it. - if (bitsAreInfOrNaN(bits) || bitsAreZero(bits)) + // If x is infinity NaN or zero, return it. + if (bits.isInfOrNaN() || bits.isZero()) return x; - bool isNeg = bits & Properties::signMask; - int exponent = getExponentFromBits(bits); + bool isNeg = bits.sign; + int exponent = bits.getExponent(); // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. - if (exponent >= static_cast(Properties::mantissaWidth)) + if (exponent >= static_cast(MantissaWidth::value)) return x; if (exponent == -1) { @@ -140,24 +132,22 @@ return T(0.0); } - uint32_t trimSize = Properties::mantissaWidth - exponent; + uint32_t trimSize = MantissaWidth::value - exponent; + bool halfBitSet = bits.mantissa & (UIntType(1) << (trimSize - 1)); + bits.mantissa = (bits.mantissa >> trimSize) << trimSize; + T truncValue = T(bits); + // If x is already an integer, return it. - if ((bits << (Properties::bitWidth - trimSize)) == 0) + if (truncValue == x) return x; - BitsType truncBits = (bits >> trimSize) << trimSize; - T truncValue = valueFromBits(truncBits); - - if ((bits & (BitsType(1) << (trimSize - 1))) == 0) { + if (!halfBitSet) { // Franctional part is less than 0.5 so round value is the // same as the trunc value. return truncValue; + } else { + return isNeg ? truncValue - T(1.0) : truncValue + T(1.0); } - - if (isNeg) - return truncValue - T(1.0); - else - return truncValue + T(1.0); } } // namespace fputil