• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
abs(T x)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>
fmin(T x,T y)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>
fmax(T x,T y)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>
fmaximum(T x,T y)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>
fminimum(T x,T y)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>
fmaximum_num(T x,T y)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>
fminimum_num(T x,T y)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>
fmaximum_mag(T x,T y)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>
fminimum_mag(T x,T y)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>
fmaximum_mag_num(T x,T y)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>
fminimum_mag_num(T x,T y)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>
fdim(T x,T y)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>
canonicalize(T & cx,const T & x)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