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 | |
21 | namespace LIBC_NAMESPACE { |
22 | namespace fputil { |
23 | |
24 | template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> |
25 | LIBC_INLINE T abs(T x) { |
26 | return FPBits<T>(x).abs().get_val(); |
27 | } |
28 | |
29 | template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> |
30 | LIBC_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 | |
45 | template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> |
46 | LIBC_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 | |
61 | template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> |
62 | LIBC_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 | |
74 | template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> |
75 | LIBC_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 | |
87 | template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> |
88 | LIBC_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 | |
104 | template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> |
105 | LIBC_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 | |
121 | template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> |
122 | LIBC_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 | |
132 | template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> |
133 | LIBC_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 | |
143 | template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> |
144 | LIBC_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 | |
154 | template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> |
155 | LIBC_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 | |
165 | template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> |
166 | LIBC_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 | |
180 | template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> |
181 | LIBC_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 | |