/src/serenity/AK/FloatingPoint.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #pragma once |
8 | | |
9 | | #include <AK/BitCast.h> |
10 | | #include <AK/StdLibExtras.h> |
11 | | #include <AK/Types.h> |
12 | | |
13 | | namespace AK { |
14 | | |
15 | | template<typename T> |
16 | | struct FloatExtractor; |
17 | | |
18 | | #ifdef AK_HAS_FLOAT_128 |
19 | | template<> |
20 | | struct FloatExtractor<f128> { |
21 | | static constexpr FloatExtractor<f128> from_float(f128 f) { return bit_cast<FloatExtractor<f128>>(f); } |
22 | | constexpr f128 to_float() const { return bit_cast<f128>(*this); } |
23 | | |
24 | | using ComponentType = unsigned __int128; |
25 | | static constexpr int mantissa_bits = 112; |
26 | | static constexpr ComponentType mantissa_max = (((ComponentType)1) << 112) - 1; |
27 | | static constexpr int exponent_bias = 16383; |
28 | | static constexpr int exponent_bits = 15; |
29 | | static constexpr unsigned exponent_max = 32767; |
30 | | |
31 | | ComponentType mantissa : 112; |
32 | | ComponentType exponent : 15; |
33 | | ComponentType sign : 1; |
34 | | }; |
35 | | // Validate that f128 and the FloatExtractor struct are 128 bits. |
36 | | static_assert(AssertSize<f128, 16>()); |
37 | | static_assert(AssertSize<FloatExtractor<f128>, sizeof(f128)>()); |
38 | | #endif |
39 | | |
40 | | #ifdef AK_HAS_FLOAT_80 |
41 | | template<> |
42 | | struct FloatExtractor<f80> { |
43 | 0 | static constexpr FloatExtractor<f80> from_float(f80 f) { return bit_cast<FloatExtractor<f80>>(f); } |
44 | 0 | constexpr f80 to_float() const { return bit_cast<f80>(*this); } |
45 | | |
46 | | using ComponentType = unsigned long long; |
47 | | static constexpr int mantissa_bits = 64; |
48 | | static constexpr ComponentType mantissa_max = ~0ull; |
49 | | static constexpr int exponent_bias = 16383; |
50 | | static constexpr int exponent_bits = 15; |
51 | | static constexpr unsigned exponent_max = 32767; |
52 | | |
53 | | // This is technically wrong: Extended floating point values really only have 63 bits of mantissa |
54 | | // and an "integer bit" that behaves in various strange, unintuitive and non-IEEE-754 ways. |
55 | | // However, since all bit-fiddling float code assumes IEEE floats, it cannot handle this properly. |
56 | | // If we pretend that 80-bit floats are IEEE floats with 64-bit mantissas, almost everything works correctly |
57 | | // and we just need a few special cases. |
58 | | ComponentType mantissa : 64; |
59 | | ComponentType exponent : 15; |
60 | | ComponentType sign : 1; |
61 | | }; |
62 | | static_assert(AssertSize<FloatExtractor<f80>, sizeof(f80)>()); |
63 | | #endif |
64 | | |
65 | | template<> |
66 | | struct FloatExtractor<f64> { |
67 | 0 | static constexpr FloatExtractor<f64> from_float(f64 f) { return bit_cast<FloatExtractor<f64>>(f); } |
68 | 0 | constexpr f64 to_float() const { return bit_cast<f64>(*this); } |
69 | | |
70 | | using ComponentType = unsigned long long; |
71 | | static constexpr int mantissa_bits = 52; |
72 | | static constexpr ComponentType mantissa_max = (1ull << 52) - 1; |
73 | | static constexpr int exponent_bias = 1023; |
74 | | static constexpr int exponent_bits = 11; |
75 | | static constexpr unsigned exponent_max = 2047; |
76 | | |
77 | | // FIXME: These types have to all be the same, otherwise this struct |
78 | | // goes from being a bitfield describing the layout of an f64 |
79 | | // into being a multibyte mess on windows. |
80 | | // Technically, '-mno-ms-bitfields' is supposed to disable this |
81 | | // very intuitive and portable behaviour on windows, but it doesn't |
82 | | // work with the msvc ABI. |
83 | | // See <https://github.com/llvm/llvm-project/issues/24757> |
84 | | ComponentType mantissa : 52; |
85 | | ComponentType exponent : 11; |
86 | | ComponentType sign : 1; |
87 | | }; |
88 | | static_assert(AssertSize<FloatExtractor<f64>, sizeof(f64)>()); |
89 | | |
90 | | #ifdef AK_LONG_DOUBLE_IS_DOUBLE |
91 | | template<> |
92 | | struct FloatExtractor<long double> : FloatExtractor<double> { |
93 | | }; |
94 | | static_assert(AssertSize<FloatExtractor<long double>, sizeof(FloatExtractor<double>)>()); |
95 | | #endif |
96 | | |
97 | | template<> |
98 | | struct FloatExtractor<f32> { |
99 | 4.00M | static constexpr FloatExtractor<f32> from_float(f32 f) { return bit_cast<FloatExtractor<f32>>(f); } |
100 | 462k | constexpr f32 to_float() const { return bit_cast<f32>(*this); } |
101 | | |
102 | | using ComponentType = unsigned; |
103 | | static constexpr int mantissa_bits = 23; |
104 | | static constexpr ComponentType mantissa_max = (1 << 23) - 1; |
105 | | static constexpr int exponent_bias = 127; |
106 | | static constexpr int exponent_bits = 8; |
107 | | static constexpr ComponentType exponent_max = 255; |
108 | | |
109 | | ComponentType mantissa : 23; |
110 | | ComponentType exponent : 8; |
111 | | ComponentType sign : 1; |
112 | | }; |
113 | | static_assert(AssertSize<FloatExtractor<f32>, sizeof(f32)>()); |
114 | | |
115 | | template<size_t S, size_t E, size_t M> |
116 | | requires(S <= 1 && E >= 1 && M >= 1 && (S + E + M) <= 64) class FloatingPointBits final { |
117 | | public: |
118 | | static size_t const signbit = S; |
119 | | static size_t const exponentbits = E; |
120 | | static size_t const mantissabits = M; |
121 | | |
122 | | template<typename T> |
123 | | requires(IsIntegral<T> && IsUnsigned<T> && sizeof(T) <= 8) constexpr FloatingPointBits(T bits) |
124 | | : m_bits(bits) |
125 | | { |
126 | | } |
127 | | |
128 | | constexpr FloatingPointBits(double value) |
129 | | : m_bits(bit_cast<u64>(value)) |
130 | | { |
131 | | } |
132 | | |
133 | | constexpr FloatingPointBits(float value) |
134 | | : m_bits(bit_cast<u32>(value)) |
135 | | { |
136 | | } |
137 | | |
138 | | double as_double() const |
139 | | requires(S == 1 && E == 11 && M == 52) |
140 | | { |
141 | | return bit_cast<double>(m_bits); |
142 | | } |
143 | | float as_float() const |
144 | | requires(S == 1 && E == 8 && M == 23) |
145 | | { |
146 | | return bit_cast<float>(static_cast<u32>(m_bits)); |
147 | | } |
148 | | u64 bits() const { return m_bits; } |
149 | | |
150 | | private: |
151 | | u64 m_bits; |
152 | | }; |
153 | | |
154 | | typedef FloatingPointBits<1, 8, 23> SingleFloatingPointBits; |
155 | | typedef FloatingPointBits<1, 11, 52> DoubleFloatingPointBits; |
156 | | |
157 | | /** |
158 | | * Convert between two IEEE 754 floating point types in any arrangement of sign, exponent and mantissa bits. |
159 | | */ |
160 | | template<typename To, typename From> |
161 | | constexpr To float_to_float(From const input) |
162 | | { |
163 | | constexpr u64 from_exponent_nonnumber = (1ull << From::exponentbits) - 1; |
164 | | constexpr u64 from_exponent_bias = (1ull << (From::exponentbits - 1)) - 1; |
165 | | constexpr u64 to_exponent_nonnumber = (1ull << To::exponentbits) - 1; |
166 | | constexpr u64 to_exponent_bias = (1ull << (To::exponentbits - 1)) - 1; |
167 | | constexpr u64 to_exponent_max = (1ull << To::exponentbits) - 2; |
168 | | |
169 | | // Deconstruct input bits to float components |
170 | | u64 from_sign = (input.bits() >> (From::exponentbits + From::mantissabits)) & From::signbit; |
171 | | u64 from_exponent = (input.bits() >> From::mantissabits) & ((1ull << From::exponentbits) - 1); |
172 | | u64 from_mantissa = input.bits() & ((1ull << From::mantissabits) - 1); |
173 | | |
174 | | u64 to_sign = from_sign & To::signbit; |
175 | | u64 to_exponent; |
176 | | u64 to_mantissa; |
177 | | auto target_value = [&to_sign, &to_exponent, &to_mantissa]() { |
178 | | return To((to_sign << (To::exponentbits + To::mantissabits)) | (to_exponent << To::mantissabits) | to_mantissa); |
179 | | }; |
180 | | |
181 | | auto shift_mantissa = [](u64 mantissa) -> u64 { |
182 | | if constexpr (From::mantissabits < To::mantissabits) |
183 | | return mantissa << (To::mantissabits - From::mantissabits); |
184 | | else |
185 | | return mantissa >> (From::mantissabits - To::mantissabits); |
186 | | }; |
187 | | |
188 | | // If target is unsigned and source is negative, clamp to 0 or keep NaN |
189 | | if constexpr (To::signbit == 0) { |
190 | | if (from_sign == 1) { |
191 | | if (from_exponent == from_exponent_nonnumber && from_mantissa > 0) { |
192 | | to_exponent = to_exponent_nonnumber; |
193 | | to_mantissa = 1; |
194 | | } else { |
195 | | to_exponent = 0; |
196 | | to_mantissa = 0; |
197 | | } |
198 | | return target_value(); |
199 | | } |
200 | | } |
201 | | |
202 | | // If the source floating point is denormalized; |
203 | | if (from_exponent == 0) { |
204 | | // If the source mantissa is 0, the value is +/-0 |
205 | | if (from_mantissa == 0) { |
206 | | to_exponent = 0; |
207 | | to_mantissa = 0; |
208 | | return target_value(); |
209 | | } |
210 | | |
211 | | // If the source has more exponent bits than the target, then the largest possible |
212 | | // source mantissa still cannot be represented in the target denormalized value. |
213 | | if constexpr (From::exponentbits > To::exponentbits) { |
214 | | to_exponent = 0; |
215 | | to_mantissa = 0; |
216 | | return target_value(); |
217 | | } |
218 | | |
219 | | // If the source and target have the same number of exponent bits, we only need to |
220 | | // shift the mantissa. |
221 | | if constexpr (From::exponentbits == To::exponentbits) { |
222 | | to_exponent = 0; |
223 | | to_mantissa = shift_mantissa(from_mantissa); |
224 | | return target_value(); |
225 | | } |
226 | | |
227 | | // The target has more exponent bits, so our denormalized value can be represented |
228 | | // as a normalized value in the target floating point. Normalized values have an |
229 | | // implicit leading 1, so we shift the mantissa left until we find our explicit |
230 | | // leading 1 which is then dropped. |
231 | | int adjust_exponent = -1; |
232 | | to_mantissa = from_mantissa; |
233 | | do { |
234 | | ++adjust_exponent; |
235 | | to_mantissa <<= 1; |
236 | | } while ((to_mantissa & (1ull << From::mantissabits)) == 0); |
237 | | to_exponent = to_exponent_bias - from_exponent_bias - adjust_exponent; |
238 | | |
239 | | // Drop the most significant bit from the mantissa |
240 | | to_mantissa &= (1ull << From::mantissabits) - 1; |
241 | | to_mantissa = shift_mantissa(to_mantissa); |
242 | | return target_value(); |
243 | | } |
244 | | |
245 | | // If the source is NaN or +/-Inf, keep it that way |
246 | | if (from_exponent == from_exponent_nonnumber) { |
247 | | to_exponent = to_exponent_nonnumber; |
248 | | to_mantissa = (from_mantissa == 0) ? 0 : 1; |
249 | | return target_value(); |
250 | | } |
251 | | |
252 | | // Determine the target exponent |
253 | | to_exponent = to_exponent_bias - from_exponent_bias + from_exponent; |
254 | | |
255 | | // If the calculated exponent exceeds the target's capacity, clamp both the exponent and the |
256 | | // mantissa to their maximum values. |
257 | | if (to_exponent > to_exponent_max) { |
258 | | to_exponent = to_exponent_max; |
259 | | to_mantissa = (1ull << To::mantissabits) - 1; |
260 | | return target_value(); |
261 | | } |
262 | | |
263 | | // If the new exponent is less than 1, we can only represent this value as a denormalized number |
264 | | if (to_exponent < 1) { |
265 | | to_exponent = 0; |
266 | | |
267 | | // Add a leading 1 and shift the mantissa right |
268 | | int adjust_exponent = 1 - to_exponent_bias - from_exponent + from_exponent_bias; |
269 | | to_mantissa = ((1ull << From::mantissabits) | from_mantissa) >> adjust_exponent; |
270 | | to_mantissa = shift_mantissa(to_mantissa); |
271 | | return target_value(); |
272 | | } |
273 | | |
274 | | // New exponent fits; shift the mantissa to fit as well |
275 | | to_mantissa = shift_mantissa(from_mantissa); |
276 | | return target_value(); |
277 | | } |
278 | | |
279 | | template<typename O> |
280 | | constexpr O convert_from_native_double(double input) { return float_to_float<O>(DoubleFloatingPointBits(input)); } |
281 | | |
282 | | template<typename O> |
283 | | constexpr O convert_from_native_float(float input) { return float_to_float<O>(SingleFloatingPointBits(input)); } |
284 | | |
285 | | template<typename I> |
286 | | constexpr double convert_to_native_double(I input) { return float_to_float<DoubleFloatingPointBits>(input).as_double(); } |
287 | | |
288 | | template<typename I> |
289 | | constexpr float convert_to_native_float(I input) { return float_to_float<SingleFloatingPointBits>(input).as_float(); } |
290 | | |
291 | | } |
292 | | |
293 | | #if USING_AK_GLOBALLY |
294 | | using AK::DoubleFloatingPointBits; |
295 | | using AK::FloatExtractor; |
296 | | using AK::FloatingPointBits; |
297 | | using AK::SingleFloatingPointBits; |
298 | | |
299 | | using AK::convert_from_native_double; |
300 | | using AK::convert_from_native_float; |
301 | | using AK::convert_to_native_double; |
302 | | using AK::convert_to_native_float; |
303 | | using AK::float_to_float; |
304 | | #endif |