brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.2 KiB · b30e36f Raw
273 lines · c
1//===-- A class to store a normalized floating point number -----*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_NORMALFLOAT_H10#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_NORMALFLOAT_H11 12#include "FPBits.h"13 14#include "hdr/stdint_proxy.h"15#include "src/__support/CPP/type_traits.h"16#include "src/__support/common.h"17#include "src/__support/macros/config.h"18 19namespace LIBC_NAMESPACE_DECL {20namespace fputil {21 22// A class which stores the normalized form of a floating point value.23// The special IEEE-754 bits patterns of Zero, infinity and NaNs are24// are not handled by this class.25//26// A normalized floating point number is of this form:27//    (-1)*sign * 2^exponent * <mantissa>28// where <mantissa> is of the form 1.<...>.29template <typename T> struct NormalFloat {30  static_assert(31      cpp::is_floating_point_v<T>,32      "NormalFloat template parameter has to be a floating point type.");33 34  using StorageType = typename FPBits<T>::StorageType;35  static constexpr StorageType ONE =36      (StorageType(1) << FPBits<T>::FRACTION_LEN);37 38  // Unbiased exponent value.39  int32_t exponent;40 41  StorageType mantissa;42  // We want |StorageType| to have atleast one bit more than the actual mantissa43  // bit width to accommodate the implicit 1 value.44  static_assert(sizeof(StorageType) * 8 >= FPBits<T>::FRACTION_LEN + 1,45                "Bad type for mantissa in NormalFloat.");46 47  Sign sign = Sign::POS;48 49  LIBC_INLINE NormalFloat(Sign s, int32_t e, StorageType m)50      : exponent(e), mantissa(m), sign(s) {51    if (mantissa >= ONE)52      return;53 54    unsigned normalization_shift = evaluate_normalization_shift(mantissa);55    mantissa <<= normalization_shift;56    exponent -= normalization_shift;57  }58 59  LIBC_INLINE explicit NormalFloat(T x) { init_from_bits(FPBits<T>(x)); }60 61  LIBC_INLINE explicit NormalFloat(FPBits<T> bits) { init_from_bits(bits); }62 63  // Compares this normalized number with another normalized number.64  // Returns -1 is this number is less than |other|, 0 if this number is equal65  // to |other|, and 1 if this number is greater than |other|.66  LIBC_INLINE int cmp(const NormalFloat<T> &other) const {67    const int result = sign.is_neg() ? -1 : 1;68    if (sign != other.sign)69      return result;70 71    if (exponent > other.exponent) {72      return result;73    } else if (exponent == other.exponent) {74      if (mantissa > other.mantissa)75        return result;76      else if (mantissa == other.mantissa)77        return 0;78      else79        return -result;80    } else {81      return -result;82    }83  }84 85  // Returns a new normalized floating point number which is equal in value86  // to this number multiplied by 2^e. That is:87  //     new = this *  2^e88  LIBC_INLINE NormalFloat<T> mul2(int e) const {89    NormalFloat<T> result = *this;90    result.exponent += e;91    return result;92  }93 94  LIBC_INLINE operator T() const {95    int biased_exponent = exponent + FPBits<T>::EXP_BIAS;96    // Max exponent is of the form 0xFF...E. That is why -2 and not -1.97    constexpr int MAX_EXPONENT_VALUE = (1 << FPBits<T>::EXP_LEN) - 2;98    if (biased_exponent > MAX_EXPONENT_VALUE) {99      return FPBits<T>::inf(sign).get_val();100    }101 102    FPBits<T> result(T(0.0));103    result.set_sign(sign);104 105    constexpr int SUBNORMAL_EXPONENT = -FPBits<T>::EXP_BIAS + 1;106    if (exponent < SUBNORMAL_EXPONENT) {107      unsigned shift = static_cast<unsigned>(SUBNORMAL_EXPONENT - exponent);108      // Since exponent > subnormalExponent, shift is strictly greater than109      // zero.110      if (shift <= FPBits<T>::FRACTION_LEN + 1) {111        // Generate a subnormal number. Might lead to loss of precision.112        // We round to nearest and round halfway cases to even.113        const StorageType shift_out_mask =114            static_cast<StorageType>(StorageType(1) << shift) - 1;115        const StorageType shift_out_value = mantissa & shift_out_mask;116        const StorageType halfway_value =117            static_cast<StorageType>(StorageType(1) << (shift - 1));118        result.set_biased_exponent(0);119        result.set_mantissa(mantissa >> shift);120        StorageType new_mantissa = result.get_mantissa();121        if (shift_out_value > halfway_value) {122          new_mantissa += 1;123        } else if (shift_out_value == halfway_value) {124          // Round to even.125          if (result.get_mantissa() & 0x1)126            new_mantissa += 1;127        }128        result.set_mantissa(new_mantissa);129        // Adding 1 to mantissa can lead to overflow. This can only happen if130        // mantissa was all ones (0b111..11). For such a case, we will carry131        // the overflow into the exponent.132        if (new_mantissa == ONE)133          result.set_biased_exponent(1);134        return result.get_val();135      } else {136        return result.get_val();137      }138    }139 140    result.set_biased_exponent(141        static_cast<StorageType>(exponent + FPBits<T>::EXP_BIAS));142    result.set_mantissa(mantissa);143    return result.get_val();144  }145 146private:147  LIBC_INLINE void init_from_bits(FPBits<T> bits) {148    sign = bits.sign();149 150    if (bits.is_inf_or_nan() || bits.is_zero()) {151      // Ignore special bit patterns. Implementations deal with them separately152      // anyway so this should not be a problem.153      exponent = 0;154      mantissa = 0;155      return;156    }157 158    // Normalize subnormal numbers.159    if (bits.is_subnormal()) {160      unsigned shift = evaluate_normalization_shift(bits.get_mantissa());161      mantissa = static_cast<StorageType>(bits.get_mantissa() << shift);162      exponent = 1 - FPBits<T>::EXP_BIAS - static_cast<int32_t>(shift);163    } else {164      exponent = bits.get_biased_exponent() - FPBits<T>::EXP_BIAS;165      mantissa = ONE | bits.get_mantissa();166    }167  }168 169  LIBC_INLINE unsigned evaluate_normalization_shift(StorageType m) {170    unsigned shift = 0;171    for (; (ONE & m) == 0 && (shift < FPBits<T>::FRACTION_LEN);172         m <<= 1, ++shift)173      ;174    return shift;175  }176};177 178#ifdef LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80179template <>180LIBC_INLINE void181NormalFloat<long double>::init_from_bits(FPBits<long double> bits) {182  sign = bits.sign();183 184  if (bits.is_inf_or_nan() || bits.is_zero()) {185    // Ignore special bit patterns. Implementations deal with them separately186    // anyway so this should not be a problem.187    exponent = 0;188    mantissa = 0;189    return;190  }191 192  if (bits.is_subnormal()) {193    if (bits.get_implicit_bit() == 0) {194      // Since we ignore zero value, the mantissa in this case is non-zero.195      int normalization_shift =196          evaluate_normalization_shift(bits.get_mantissa());197      exponent = -16382 - normalization_shift;198      mantissa = (bits.get_mantissa() << normalization_shift);199    } else {200      exponent = -16382;201      mantissa = ONE | bits.get_mantissa();202    }203  } else {204    if (bits.get_implicit_bit() == 0) {205      // Invalid number so just store 0 similar to a NaN.206      exponent = 0;207      mantissa = 0;208    } else {209      exponent = bits.get_biased_exponent() - 16383;210      mantissa = ONE | bits.get_mantissa();211    }212  }213}214 215template <> LIBC_INLINE NormalFloat<long double>::operator long double() const {216  using LDBits = FPBits<long double>;217  int biased_exponent = exponent + LDBits::EXP_BIAS;218  // Max exponent is of the form 0xFF...E. That is why -2 and not -1.219  constexpr int MAX_EXPONENT_VALUE = (1 << LDBits::EXP_LEN) - 2;220  if (biased_exponent > MAX_EXPONENT_VALUE) {221    return LDBits::inf(sign).get_val();222  }223 224  FPBits<long double> result(0.0l);225  result.set_sign(sign);226 227  constexpr int SUBNORMAL_EXPONENT = -LDBits::EXP_BIAS + 1;228  if (exponent < SUBNORMAL_EXPONENT) {229    unsigned shift = SUBNORMAL_EXPONENT - exponent;230    if (shift <= LDBits::FRACTION_LEN + 1) {231      // Generate a subnormal number. Might lead to loss of precision.232      // We round to nearest and round halfway cases to even.233      const StorageType shift_out_mask = (StorageType(1) << shift) - 1;234      const StorageType shift_out_value = mantissa & shift_out_mask;235      const StorageType halfway_value = StorageType(1) << (shift - 1);236      result.set_biased_exponent(0);237      result.set_mantissa(mantissa >> shift);238      StorageType new_mantissa = result.get_mantissa();239      if (shift_out_value > halfway_value) {240        new_mantissa += 1;241      } else if (shift_out_value == halfway_value) {242        // Round to even.243        if (result.get_mantissa() & 0x1)244          new_mantissa += 1;245      }246      result.set_mantissa(new_mantissa);247      // Adding 1 to mantissa can lead to overflow. This can only happen if248      // mantissa was all ones (0b111..11). For such a case, we will carry249      // the overflow into the exponent and set the implicit bit to 1.250      if (new_mantissa == ONE) {251        result.set_biased_exponent(1);252        result.set_implicit_bit(1);253      } else {254        result.set_implicit_bit(0);255      }256      return result.get_val();257    } else {258      return result.get_val();259    }260  }261 262  result.set_biased_exponent(biased_exponent);263  result.set_mantissa(mantissa);264  result.set_implicit_bit(1);265  return result.get_val();266}267#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80268 269} // namespace fputil270} // namespace LIBC_NAMESPACE_DECL271 272#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_NORMALFLOAT_H273