blob: e5ac101fedc0e32cd715e5bfea62f85c54d5b4bb [file] [log] [blame]
//===-- Basic operations on floating point numbers --------------*- 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___SUPPORT_FPUTIL_BASICOPERATIONS_H
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_BASICOPERATIONS_H
#include "FEnvImpl.h"
#include "FPBits.h"
#include "FEnvImpl.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/common.h"
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
#include "src/__support/uint128.h"
namespace LIBC_NAMESPACE {
namespace fputil {
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T abs(T x) {
return FPBits<T>(x).abs().get_val();
}
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T fmin(T x, T y) {
const FPBits<T> bitx(x), bity(y);
if (bitx.is_nan())
return y;
if (bity.is_nan())
return x;
if (bitx.sign() != bity.sign())
// To make sure that fmin(+0, -0) == -0 == fmin(-0, +0), whenever x and
// y has different signs and both are not NaNs, we return the number
// with negative sign.
return bitx.is_neg() ? x : y;
return x < y ? x : y;
}
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T fmax(T x, T y) {
FPBits<T> bitx(x), bity(y);
if (bitx.is_nan())
return y;
if (bity.is_nan())
return x;
if (bitx.sign() != bity.sign())
// To make sure that fmax(+0, -0) == +0 == fmax(-0, +0), whenever x and
// y has different signs and both are not NaNs, we return the number
// with positive sign.
return bitx.is_neg() ? y : x;
return x > y ? x : y;
}
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T fmaximum(T x, T y) {
FPBits<T> bitx(x), bity(y);
if (bitx.is_nan())
return x;
if (bity.is_nan())
return y;
if (bitx.sign() != bity.sign())
return (bitx.is_neg() ? y : x);
return x > y ? x : y;
}
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T fminimum(T x, T y) {
const FPBits<T> bitx(x), bity(y);
if (bitx.is_nan())
return x;
if (bity.is_nan())
return y;
if (bitx.sign() != bity.sign())
return (bitx.is_neg()) ? x : y;
return x < y ? x : y;
}
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T fmaximum_num(T x, T y) {
FPBits<T> bitx(x), bity(y);
if (bitx.is_signaling_nan() || bity.is_signaling_nan()) {
fputil::raise_except_if_required(FE_INVALID);
if (bitx.is_nan() && bity.is_nan())
return FPBits<T>::quiet_nan().get_val();
}
if (bitx.is_nan())
return y;
if (bity.is_nan())
return x;
if (bitx.sign() != bity.sign())
return (bitx.is_neg() ? y : x);
return x > y ? x : y;
}
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T fminimum_num(T x, T y) {
FPBits<T> bitx(x), bity(y);
if (bitx.is_signaling_nan() || bity.is_signaling_nan()) {
fputil::raise_except_if_required(FE_INVALID);
if (bitx.is_nan() && bity.is_nan())
return FPBits<T>::quiet_nan().get_val();
}
if (bitx.is_nan())
return y;
if (bity.is_nan())
return x;
if (bitx.sign() != bity.sign())
return (bitx.is_neg() ? x : y);
return x < y ? x : y;
}
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T fmaximum_mag(T x, T y) {
FPBits<T> bitx(x), bity(y);
if (abs(x) > abs(y))
return x;
if (abs(y) > abs(x))
return y;
return fmaximum(x, y);
}
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T fminimum_mag(T x, T y) {
FPBits<T> bitx(x), bity(y);
if (abs(x) < abs(y))
return x;
if (abs(y) < abs(x))
return y;
return fminimum(x, y);
}
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T fmaximum_mag_num(T x, T y) {
FPBits<T> bitx(x), bity(y);
if (abs(x) > abs(y))
return x;
if (abs(y) > abs(x))
return y;
return fmaximum_num(x, y);
}
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T fminimum_mag_num(T x, T y) {
FPBits<T> bitx(x), bity(y);
if (abs(x) < abs(y))
return x;
if (abs(y) < abs(x))
return y;
return fminimum_num(x, y);
}
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T fdim(T x, T y) {
FPBits<T> bitx(x), bity(y);
if (bitx.is_nan()) {
return x;
}
if (bity.is_nan()) {
return y;
}
return (x > y ? x - y : 0);
}
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE int canonicalize(T &cx, const T &x) {
FPBits<T> sx(x);
if constexpr (get_fp_type<T>() == FPType::X86_Binary80) {
// All the pseudo and unnormal numbers are not canonical.
// More precisely :
// Exponent | Significand | Meaning
// | Bits 63-62 | Bits 61-0 |
// All Ones | 00 | Zero | Pseudo Infinity, Value = SNaN
// All Ones | 00 | Non-Zero | Pseudo NaN, Value = SNaN
// All Ones | 01 | Anything | Pseudo NaN, Value = SNaN
// | Bit 63 | Bits 62-0 |
// All zeroes | One | Anything | Pseudo Denormal, Value =
// | | | (−1)**s × m × 2**−16382
// All Other | Zero | Anything | Unnormal, Value = SNaN
// Values | | |
bool bit63 = sx.get_implicit_bit();
UInt128 mantissa = sx.get_explicit_mantissa();
bool bit62 = static_cast<bool>((mantissa & (1ULL << 62)) >> 62);
int exponent = sx.get_biased_exponent();
if (exponent == 0x7FFF) {
if (!bit63 && !bit62) {
if (mantissa == 0) {
cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
raise_except_if_required(FE_INVALID);
return 1;
}
cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
raise_except_if_required(FE_INVALID);
return 1;
} else if (!bit63 && bit62) {
cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
raise_except_if_required(FE_INVALID);
return 1;
} else if (LIBC_UNLIKELY(sx.is_signaling_nan())) {
cx = FPBits<T>::quiet_nan(sx.sign(), sx.get_explicit_mantissa())
.get_val();
raise_except_if_required(FE_INVALID);
return 1;
} else
cx = x;
} else if (exponent == 0 && bit63)
cx = FPBits<T>::make_value(mantissa, 0).get_val();
else if (exponent != 0 && !bit63) {
cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
raise_except_if_required(FE_INVALID);
return 1;
} else if (LIBC_UNLIKELY(sx.is_signaling_nan())) {
cx =
FPBits<T>::quiet_nan(sx.sign(), sx.get_explicit_mantissa()).get_val();
raise_except_if_required(FE_INVALID);
return 1;
} else
cx = x;
} else if (LIBC_UNLIKELY(sx.is_signaling_nan())) {
cx = FPBits<T>::quiet_nan(sx.sign(), sx.get_explicit_mantissa()).get_val();
raise_except_if_required(FE_INVALID);
return 1;
} else
cx = x;
return 0;
}
} // namespace fputil
} // namespace LIBC_NAMESPACE
#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_BASICOPERATIONS_H