1//===-- Comparison operations on floating point numbers ---------*- 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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISONOPERATIONS_H
10#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISONOPERATIONS_H
11
12#include "FEnvImpl.h"
13#include "FPBits.h"
14#include "src/__support/CPP/type_traits.h"
15#include "src/__support/macros/config.h"
16
17namespace LIBC_NAMESPACE_DECL {
18namespace fputil {
19
20// All predicates are hereby implemented as per IEEE Std 754-2019
21// Implements compareQuietEqual predicate
22// Rules for comparison within the same floating point type
23// 1. +0 = −0
24// 2. (i) +inf = +inf
25// (ii) -inf = -inf
26// (iii) -inf != +inf
27// 3. Any comparison with NaN returns false
28template <typename T>
29LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
30equals(T x, T y) {
31 using FPBits = FPBits<T>;
32 FPBits x_bits(x);
33 FPBits y_bits(y);
34
35 if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
36 fputil::raise_except_if_required(FE_INVALID);
37
38 // NaN == x returns false for every x
39 if (x_bits.is_nan() || y_bits.is_nan())
40 return false;
41
42 // +/- 0 == +/- 0
43 if (x_bits.is_zero() && y_bits.is_zero())
44 return true;
45
46 return x_bits.uintval() == y_bits.uintval();
47}
48
49// Implements compareSignalingLess predicate
50// Section 5.11 Rules:
51// 1. -inf < x (x != -inf)
52// 2. x < +inf (x != +inf)
53// 3. Any comparison with NaN return false
54template <typename T>
55LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
56less_than(T x, T y) {
57 using FPBits = FPBits<T>;
58 FPBits x_bits(x);
59 FPBits y_bits(y);
60
61 // Any comparison with NaN returns false
62 if (x_bits.is_nan() || y_bits.is_nan()) {
63 fputil::raise_except_if_required(FE_INVALID);
64 return false;
65 }
66
67 if (x_bits.is_zero() && y_bits.is_zero())
68 return false;
69
70 if (x_bits.is_neg() && y_bits.is_pos())
71 return true;
72
73 if (x_bits.is_pos() && y_bits.is_neg())
74 return false;
75
76 // since floating-point numbers are stored in the format: s | e | m
77 // we can directly compare the uintval's
78
79 // both negative
80 if (x_bits.is_neg())
81 return x_bits.uintval() > y_bits.uintval();
82
83 // both positive
84 return x_bits.uintval() < y_bits.uintval();
85}
86
87// Implements compareSignalingGreater predicate
88// x < y => y > x
89template <typename T>
90LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
91greater_than(T x, T y) {
92 return less_than(y, x);
93}
94
95// Implements compareSignalingLessEqual predicate
96// x <= y => (x < y) || (x == y)
97template <typename T>
98LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
99less_than_or_equals(T x, T y) {
100 return less_than(x, y) || equals(x, y);
101}
102
103// Implements compareSignalingGreaterEqual predicate
104// x >= y => (x > y) || (x == y) => (y < x) || (x == y)
105template <typename T>
106LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
107greater_than_or_equals(T x, T y) {
108 return less_than(y, x) || equals(x, y);
109}
110
111} // namespace fputil
112} // namespace LIBC_NAMESPACE_DECL
113
114#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISONOPERATIONS_H
115