From 1caedd0c550646557d8d2feb97b3cbba8c48b2d7 Mon Sep 17 00:00:00 2001 From: Siva Chandra Reddy Date: Mon, 18 May 2020 15:06:01 -0700 Subject: [libc] Add implementations of ceil[f], floor[f] and trunc[f] from math.h. Reviewers: abrachet Differential Revision: https://reviews.llvm.org/D80612 --- libc/utils/FPUtil/FloatOperations.h | 125 +++++++++++++++++++++++++++++++++-- libc/utils/FPUtil/FloatProperties.h | 6 ++ libc/utils/MPFRWrapper/MPFRUtils.cpp | 12 ++++ libc/utils/MPFRWrapper/MPFRUtils.h | 12 +++- 4 files changed, 147 insertions(+), 8 deletions(-) (limited to 'libc/utils') diff --git a/libc/utils/FPUtil/FloatOperations.h b/libc/utils/FPUtil/FloatOperations.h index ff7604b..a378903 100644 --- a/libc/utils/FPUtil/FloatOperations.h +++ b/libc/utils/FPUtil/FloatOperations.h @@ -40,18 +40,23 @@ static inline typename FloatProperties::BitsType absBits(T x) { return valueAsBits(x) & (~FloatProperties::signMask); } -// Return the zero adjusted exponent value of x. -template ::Value, int> = 0> -int getExponent(T x) { - using Properties = FloatProperties; - using BitsType = typename Properties::BitsType; - BitsType bits = absBits(x); +template +static inline int getExponentFromBits(BitsType bits) { + using FPType = typename FloatType::Type; + using Properties = FloatProperties; + bits &= Properties::exponentMask; int e = (bits >> Properties::mantissaWidth); // Shift out the mantissa. e -= Properties::exponentOffset; // Zero adjust. return e; } +// Return the zero adjusted exponent value of x. +template ::Value, int> = 0> +static inline int getExponent(T x) { + return getExponentFromBits(valueAsBits(x)); +} + // Return true if x is infinity (positive or negative.) template ::Value, int> = 0> @@ -74,6 +79,24 @@ static inline bool isNaN(T x) { ((bits & Properties::mantissaMask) != 0); } +template static inline bool bitsAreInfOrNaN(BitsType bits) { + using FPType = typename FloatType::Type; + return (bits & BitPatterns::inf) == BitPatterns::inf; +} + +template static inline bool bitsAreZero(BitsType bits) { + using FPType = typename FloatType::Type; + return (bits == BitPatterns::zero) || + (bits == BitPatterns::negZero); +} + +// Return true if x is any kind of NaN or infinity. +template ::Value, int> = 0> +static inline bool isInfOrNaN(T x) { + return bitsAreInfOrNaN(valueAsBits(x)); +} + // Return true if x is a quiet NAN. template ::Value, int> = 0> @@ -103,6 +126,94 @@ static inline T abs(T x) { return valueFromBits(absBits(x)); } +// Return the trucated value of x. If x is non-negative, then the return value +// is greatest integer less than or equal to x. Otherwise, return the smallest +// integer greater than or equal to x. That is, return the integer value rounded +// toward zero. +template ::Value, int> = 0> +static inline T trunc(T x) { + using Properties = FloatProperties; + using BitsType = typename FloatProperties::BitsType; + + BitsType bits = valueAsBits(x); + + // If x is infinity, NaN or zero, return it. + if (bitsAreInfOrNaN(bits) || bitsAreZero(bits)) + return x; + + int exponent = getExponentFromBits(bits); + + // If the exponent is greater than the most negative mantissa + // exponent, then x is already an integer. + if (exponent >= static_cast(Properties::mantissaWidth)) + return x; + + // If the exponent is such that abs(x) is less than 1, then return 0. + if (exponent <= -1) { + if (Properties::signMask & bits) + return T(-0.0); + else + return T(0.0); + } + + uint32_t trimSize = Properties::mantissaWidth - exponent; + return valueFromBits((bits >> trimSize) << trimSize); +} + +template ::Value, int> = 0> +static inline T ceil(T x) { + using Properties = FloatProperties; + using BitsType = typename FloatProperties::BitsType; + + BitsType bits = valueAsBits(x); + + // If x is infinity NaN or zero, return it. + if (bitsAreInfOrNaN(bits) || bitsAreZero(bits)) + return x; + + bool isNeg = bits & Properties::signMask; + int exponent = getExponentFromBits(bits); + + // If the exponent is greater than the most negative mantissa + // exponent, then x is already an integer. + if (exponent >= static_cast(Properties::mantissaWidth)) + return x; + + if (exponent <= -1) { + if (isNeg) + return T(-0.0); + else + return T(1.0); + } + + uint32_t trimSize = Properties::mantissaWidth - exponent; + // If x is already an integer, return it. + if ((bits << (Properties::bitWidth - trimSize)) == 0) + 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; + + return truncValue + T(1.0); +} + +template ::Value, int> = 0> +static inline T floor(T x) { + auto bits = valueAsBits(x); + if (FloatProperties::signMask & bits) { + return -ceil(-x); + } else { + return trunc(x); + } +} + } // namespace fputil } // namespace __llvm_libc diff --git a/libc/utils/FPUtil/FloatProperties.h b/libc/utils/FPUtil/FloatProperties.h index a9584c7..fb09172 100644 --- a/libc/utils/FPUtil/FloatProperties.h +++ b/libc/utils/FPUtil/FloatProperties.h @@ -21,9 +21,12 @@ template <> struct FloatProperties { static_assert(sizeof(BitsType) == sizeof(float), "Unexpected size of 'float' type."); + static constexpr uint32_t bitWidth = sizeof(BitsType) << 3; + static constexpr uint32_t mantissaWidth = 23; static constexpr BitsType mantissaMask = 0x007fffffU; static constexpr BitsType signMask = 0x80000000U; + static constexpr BitsType exponentMask = ~(signMask | mantissaMask); static constexpr uint32_t exponentOffset = 127; // If a number x is a NAN, then it is a quiet NAN if: @@ -37,9 +40,12 @@ template <> struct FloatProperties { static_assert(sizeof(BitsType) == sizeof(double), "Unexpected size of 'double' type."); + static constexpr uint32_t bitWidth = sizeof(BitsType) << 3; + static constexpr uint32_t mantissaWidth = 52; static constexpr BitsType mantissaMask = 0x000fffffffffffffU; static constexpr BitsType signMask = 0x8000000000000000ULL; + static constexpr BitsType exponentMask = ~(signMask | mantissaMask); static constexpr uint32_t exponentOffset = 1023; // If a number x is a NAN, then it is a quiet NAN if: diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp index 51c8c37..1bbc84d 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -89,6 +89,9 @@ public: case Operation::Abs: mpfr_abs(value, mpfrInput.value, MPFR_RNDN); break; + case Operation::Ceil: + mpfr_ceil(value, mpfrInput.value); + break; case Operation::Cos: mpfr_cos(value, mpfrInput.value, MPFR_RNDN); break; @@ -98,9 +101,18 @@ public: case Operation::Exp2: mpfr_exp2(value, mpfrInput.value, MPFR_RNDN); break; + case Operation::Floor: + mpfr_floor(value, mpfrInput.value); + break; + case Operation::Round: + mpfr_round(value, mpfrInput.value); + break; case Operation::Sin: mpfr_sin(value, mpfrInput.value, MPFR_RNDN); break; + case Operation::Trunc: + mpfr_trunc(value, mpfrInput.value); + break; } } diff --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h index e39ed91..5628165 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.h +++ b/libc/utils/MPFRWrapper/MPFRUtils.h @@ -39,7 +39,17 @@ struct Tolerance { uint32_t bits; }; -enum class Operation : int { Abs, Cos, Exp, Exp2, Sin }; +enum class Operation : int { + Abs, + Ceil, + Cos, + Exp, + Exp2, + Floor, + Round, + Sin, + Trunc +}; namespace internal { -- cgit v1.1