blob: ff62ce085513b73101be1e960b118126f42460ae [file]
//===-- Comparison 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_COMPARISONOPERATIONS_H
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISONOPERATIONS_H
#include "FEnvImpl.h"
#include "FPBits.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
namespace fputil {
// All predicates are hereby implemented as per IEEE Std 754-2019
// Implements compareQuietEqual predicate
// Rules for comparison within the same floating point type
// 1. +0 = −0
// 2. (i) +inf = +inf
// (ii) -inf = -inf
// (iii) -inf != +inf
// 3. Any comparison with NaN returns false
template <typename T>
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> equals(T x,
T y) {
using FPBits = FPBits<T>;
FPBits x_bits(x);
FPBits y_bits(y);
if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
fputil::raise_except_if_required(FE_INVALID);
// NaN == x returns false for every x
if (x_bits.is_nan() || y_bits.is_nan())
return false;
// +/- 0 == +/- 0
if (x_bits.is_zero() && y_bits.is_zero())
return true;
return x_bits.uintval() == y_bits.uintval();
}
// Implements compareSignalingLess predicate
// Section 5.11 Rules:
// 1. -inf < x (x != -inf)
// 2. x < +inf (x != +inf)
// 3. Any comparison with NaN return false
template <typename T>
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> less_than(T x,
T y) {
using FPBits = FPBits<T>;
FPBits x_bits(x);
FPBits y_bits(y);
// Any comparison with NaN returns false
if (x_bits.is_nan() || y_bits.is_nan()) {
fputil::raise_except_if_required(FE_INVALID);
return false;
}
if (x_bits.is_zero() && y_bits.is_zero())
return false;
if (x_bits.is_neg() && y_bits.is_pos())
return true;
if (x_bits.is_pos() && y_bits.is_neg())
return false;
// since floating-point numbers are stored in the format: s | e | m
// we can directly compare the uintval's
// both negative
if (x_bits.is_neg())
return x_bits.uintval() > y_bits.uintval();
// both positive
return x_bits.uintval() < y_bits.uintval();
}
// Implements compareSignalingGreater predicate
// x < y => y > x
template <typename T>
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
greater_than(T x, T y) {
return less_than(y, x);
}
// Implements compareSignalingLessEqual predicate
// x <= y => (x < y) || (x == y)
template <typename T>
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
less_than_or_equals(T x, T y) {
return less_than(x, y) || equals(x, y);
}
// Implements compareSignalingGreaterEqual predicate
// x >= y => (x > y) || (x == y) => (y < x) || (x == y)
template <typename T>
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
greater_than_or_equals(T x, T y) {
return less_than(y, x) || equals(x, y);
}
} // namespace fputil
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISONOPERATIONS_H