1//===-- Basic 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_BASICOPERATIONS_H
10#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_BASICOPERATIONS_H
11
12#include "FEnvImpl.h"
13#include "FPBits.h"
14
15#include "FEnvImpl.h"
16#include "src/__support/CPP/type_traits.h"
17#include "src/__support/common.h"
18#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
19#include "src/__support/uint128.h"
20
21namespace LIBC_NAMESPACE {
22namespace fputil {
23
24template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
25LIBC_INLINE T abs(T x) {
26 return FPBits<T>(x).abs().get_val();
27}
28
29template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
30LIBC_INLINE T fmin(T x, T y) {
31 const FPBits<T> bitx(x), bity(y);
32
33 if (bitx.is_nan())
34 return y;
35 if (bity.is_nan())
36 return x;
37 if (bitx.sign() != bity.sign())
38 // To make sure that fmin(+0, -0) == -0 == fmin(-0, +0), whenever x and
39 // y has different signs and both are not NaNs, we return the number
40 // with negative sign.
41 return bitx.is_neg() ? x : y;
42 return x < y ? x : y;
43}
44
45template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
46LIBC_INLINE T fmax(T x, T y) {
47 FPBits<T> bitx(x), bity(y);
48
49 if (bitx.is_nan())
50 return y;
51 if (bity.is_nan())
52 return x;
53 if (bitx.sign() != bity.sign())
54 // To make sure that fmax(+0, -0) == +0 == fmax(-0, +0), whenever x and
55 // y has different signs and both are not NaNs, we return the number
56 // with positive sign.
57 return bitx.is_neg() ? y : x;
58 return x > y ? x : y;
59}
60
61template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
62LIBC_INLINE T fmaximum(T x, T y) {
63 FPBits<T> bitx(x), bity(y);
64
65 if (bitx.is_nan())
66 return x;
67 if (bity.is_nan())
68 return y;
69 if (bitx.sign() != bity.sign())
70 return (bitx.is_neg() ? y : x);
71 return x > y ? x : y;
72}
73
74template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
75LIBC_INLINE T fminimum(T x, T y) {
76 const FPBits<T> bitx(x), bity(y);
77
78 if (bitx.is_nan())
79 return x;
80 if (bity.is_nan())
81 return y;
82 if (bitx.sign() != bity.sign())
83 return (bitx.is_neg()) ? x : y;
84 return x < y ? x : y;
85}
86
87template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
88LIBC_INLINE T fmaximum_num(T x, T y) {
89 FPBits<T> bitx(x), bity(y);
90 if (bitx.is_signaling_nan() || bity.is_signaling_nan()) {
91 fputil::raise_except_if_required(FE_INVALID);
92 if (bitx.is_nan() && bity.is_nan())
93 return FPBits<T>::quiet_nan().get_val();
94 }
95 if (bitx.is_nan())
96 return y;
97 if (bity.is_nan())
98 return x;
99 if (bitx.sign() != bity.sign())
100 return (bitx.is_neg() ? y : x);
101 return x > y ? x : y;
102}
103
104template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
105LIBC_INLINE T fminimum_num(T x, T y) {
106 FPBits<T> bitx(x), bity(y);
107 if (bitx.is_signaling_nan() || bity.is_signaling_nan()) {
108 fputil::raise_except_if_required(FE_INVALID);
109 if (bitx.is_nan() && bity.is_nan())
110 return FPBits<T>::quiet_nan().get_val();
111 }
112 if (bitx.is_nan())
113 return y;
114 if (bity.is_nan())
115 return x;
116 if (bitx.sign() != bity.sign())
117 return (bitx.is_neg() ? x : y);
118 return x < y ? x : y;
119}
120
121template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
122LIBC_INLINE T fmaximum_mag(T x, T y) {
123 FPBits<T> bitx(x), bity(y);
124
125 if (abs(x) > abs(y))
126 return x;
127 if (abs(y) > abs(x))
128 return y;
129 return fmaximum(x, y);
130}
131
132template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
133LIBC_INLINE T fminimum_mag(T x, T y) {
134 FPBits<T> bitx(x), bity(y);
135
136 if (abs(x) < abs(y))
137 return x;
138 if (abs(y) < abs(x))
139 return y;
140 return fminimum(x, y);
141}
142
143template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
144LIBC_INLINE T fmaximum_mag_num(T x, T y) {
145 FPBits<T> bitx(x), bity(y);
146
147 if (abs(x) > abs(y))
148 return x;
149 if (abs(y) > abs(x))
150 return y;
151 return fmaximum_num(x, y);
152}
153
154template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
155LIBC_INLINE T fminimum_mag_num(T x, T y) {
156 FPBits<T> bitx(x), bity(y);
157
158 if (abs(x) < abs(y))
159 return x;
160 if (abs(y) < abs(x))
161 return y;
162 return fminimum_num(x, y);
163}
164
165template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
166LIBC_INLINE T fdim(T x, T y) {
167 FPBits<T> bitx(x), bity(y);
168
169 if (bitx.is_nan()) {
170 return x;
171 }
172
173 if (bity.is_nan()) {
174 return y;
175 }
176
177 return (x > y ? x - y : 0);
178}
179
180template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
181LIBC_INLINE int canonicalize(T &cx, const T &x) {
182 FPBits<T> sx(x);
183 if constexpr (get_fp_type<T>() == FPType::X86_Binary80) {
184 // All the pseudo and unnormal numbers are not canonical.
185 // More precisely :
186 // Exponent | Significand | Meaning
187 // | Bits 63-62 | Bits 61-0 |
188 // All Ones | 00 | Zero | Pseudo Infinity, Value = SNaN
189 // All Ones | 00 | Non-Zero | Pseudo NaN, Value = SNaN
190 // All Ones | 01 | Anything | Pseudo NaN, Value = SNaN
191 // | Bit 63 | Bits 62-0 |
192 // All zeroes | One | Anything | Pseudo Denormal, Value =
193 // | | | (−1)**s × m × 2**−16382
194 // All Other | Zero | Anything | Unnormal, Value = SNaN
195 // Values | | |
196 bool bit63 = sx.get_implicit_bit();
197 UInt128 mantissa = sx.get_explicit_mantissa();
198 bool bit62 = static_cast<bool>((mantissa & (1ULL << 62)) >> 62);
199 int exponent = sx.get_biased_exponent();
200 if (exponent == 0x7FFF) {
201 if (!bit63 && !bit62) {
202 if (mantissa == 0) {
203 cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
204 raise_except_if_required(FE_INVALID);
205 return 1;
206 }
207 cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
208 raise_except_if_required(FE_INVALID);
209 return 1;
210 } else if (!bit63 && bit62) {
211 cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
212 raise_except_if_required(FE_INVALID);
213 return 1;
214 } else if (LIBC_UNLIKELY(sx.is_signaling_nan())) {
215 cx = FPBits<T>::quiet_nan(sx.sign(), sx.get_explicit_mantissa())
216 .get_val();
217 raise_except_if_required(FE_INVALID);
218 return 1;
219 } else
220 cx = x;
221 } else if (exponent == 0 && bit63)
222 cx = FPBits<T>::make_value(mantissa, 0).get_val();
223 else if (exponent != 0 && !bit63) {
224 cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
225 raise_except_if_required(FE_INVALID);
226 return 1;
227 } else if (LIBC_UNLIKELY(sx.is_signaling_nan())) {
228 cx =
229 FPBits<T>::quiet_nan(sx.sign(), sx.get_explicit_mantissa()).get_val();
230 raise_except_if_required(FE_INVALID);
231 return 1;
232 } else
233 cx = x;
234 } else if (LIBC_UNLIKELY(sx.is_signaling_nan())) {
235 cx = FPBits<T>::quiet_nan(sx.sign(), sx.get_explicit_mantissa()).get_val();
236 raise_except_if_required(FE_INVALID);
237 return 1;
238 } else
239 cx = x;
240 return 0;
241}
242
243} // namespace fputil
244} // namespace LIBC_NAMESPACE
245
246#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_BASICOPERATIONS_H
247

source code of libc/src/__support/FPUtil/BasicOperations.h