File: ieee754_format.h

package info (click to toggle)
webkit2gtk 2.48.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, trixie
  • size: 429,620 kB
  • sloc: cpp: 3,696,936; javascript: 194,444; ansic: 169,997; python: 46,499; asm: 19,276; ruby: 18,528; perl: 16,602; xml: 4,650; yacc: 2,360; sh: 2,098; java: 1,993; lex: 1,327; pascal: 366; makefile: 298
file content (301 lines) | stat: -rw-r--r-- 12,512 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
/*
 * Copyright (C) 2023 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * License header from dragonbox
 *    https://github.com/jk-jeon/dragonbox/blob/master/LICENSE-Boost
 *    https://github.com/jk-jeon/dragonbox/blob/master/LICENSE-Apache2-LLVM
 */

#pragma once

#include <wtf/dragonbox/detail/util.h>

namespace WTF {

namespace dragonbox {

// These classes expose encoding specs of IEEE-754-like floating-point formats.
// Currently available formats are IEEE754-binary32 & IEEE754-binary64.
struct ieee754_binary32 {
    static constexpr int32_t significand_bits = 23;
    static constexpr int32_t exponent_bits = 8;
    static constexpr int32_t min_exponent = -126;
    static constexpr int32_t max_exponent = 127;
    static constexpr int32_t exponent_bias = -127;
    static constexpr int32_t decimal_digits = 9;
};

struct ieee754_binary64 {
    static constexpr int32_t significand_bits = 52;
    static constexpr int32_t exponent_bits = 11;
    static constexpr int32_t min_exponent = -1022;
    static constexpr int32_t max_exponent = 1023;
    static constexpr int32_t exponent_bias = -1023;
    static constexpr int32_t decimal_digits = 17;
};

// A floating-point traits class defines ways to interpret a bit pattern of given size as an
// encoding of floating-point number. This is a default implementation of such a traits
// class, supporting ways to interpret 32-bits into a binary32-encoded floating-point number
// and to interpret 64-bits into a binary64-encoded floating-point number. Users might
// specialize this class to change the default behavior for certain types.
template<class T>
struct default_float_traits {
    // I don't know if there is a truly reliable way of detecting
    // IEEE-754 binary32/binary64 formats; I just did my best here.
    static_assert(std::numeric_limits<T>::is_iec559
        && std::numeric_limits<T>::radix == 2
        && (detail::physical_bits<T>::value == 32 || detail::physical_bits<T>::value == 64),
        "default_ieee754_traits only works for 32-bits or 64-bits types "
        "supporting binary32 or binary64 formats!");

    // The type that is being viewed.
    using type = T;

    // Refers to the format specification class.
    using format = typename std::conditional<detail::physical_bits<T>::value == 32, ieee754_binary32, ieee754_binary64>::type;

    // Defines an unsigned integer type that is large enough to carry a variable of type T.
    // Most of the operations will be done on this integer type.
    using carrier_uint = typename std::conditional<detail::physical_bits<T>::value == 32, uint32_t, uint64_t>::type;
    static_assert(sizeof(carrier_uint) == sizeof(T), "");

    // Number of bits in the above unsigned integer type.
    static constexpr int32_t carrier_bits = static_cast<int32_t>(detail::physical_bits<carrier_uint>::value);

    // Convert from carrier_uint into the original type.
    // Depending on the floating-point encoding format, this operation might not be possible
    // for some specific bit patterns. However, the contract is that u always denotes a
    // valid bit pattern, so this function must be assumed to be noexcept.
    static constexpr T carrier_to_float(carrier_uint u) noexcept
    {
        return std::bit_cast<T>(u);
    }

    // Same as above.
    static constexpr carrier_uint float_to_carrier(T x) noexcept
    {
        return std::bit_cast<carrier_uint>(x);
    }

    // Extract exponent bits from a bit pattern.
    // The result must be aligned to the LSB so that there is no additional zero paddings
    // on the right. This function does not do bias adjustment.
    static constexpr unsigned extract_exponent_bits(carrier_uint u) noexcept
    {
        static_assert(detail::value_bits<unsigned>::value > format::exponent_bits, "");
        return static_cast<unsigned>(u >> format::significand_bits) & ((static_cast<unsigned>(1) << format::exponent_bits) - 1);
    }

    // Extract significand bits from a bit pattern.
    // The result must be aligned to the LSB so that there is no additional zero paddings
    // on the right. The result does not contain the implicit bit.
    static constexpr carrier_uint extract_significand_bits(carrier_uint u) noexcept
    {
        return static_cast<carrier_uint>(u & static_cast<carrier_uint>((static_cast<carrier_uint>(1) << format::significand_bits) - 1));
    }

    // Remove the exponent bits and extract significand bits together with the sign bit.
    static constexpr carrier_uint remove_exponent_bits(carrier_uint u, unsigned exponent_bits) noexcept
    {
        return u ^ (static_cast<carrier_uint>(exponent_bits) << format::significand_bits);
    }

    // Shift the obtained signed significand bits to the left by 1 to remove the sign bit.
    static constexpr carrier_uint remove_sign_bit_and_shift(carrier_uint u) noexcept
    {
        return static_cast<carrier_uint>(static_cast<carrier_uint>(u) << 1);
    }

    // The actual value of exponent is obtained by adding this value to the extracted
    // exponent bits.
    static constexpr int32_t exponent_bias = 1 - (1 << (carrier_bits - format::significand_bits - 2));

    // Obtain the actual value of the binary exponent from the extracted exponent bits.
    static constexpr int32_t binary_exponent(unsigned exponent_bits) noexcept
    {
        return !exponent_bits ? format::min_exponent : static_cast<int32_t>(exponent_bits) + format::exponent_bias;
    }

    // Obtain the actual value of the binary exponent from the extracted significand bits
    // and exponent bits.
    static constexpr carrier_uint binary_significand(carrier_uint significand_bits, unsigned exponent_bits) noexcept
    {
        return !exponent_bits ? significand_bits : (significand_bits | (static_cast<carrier_uint>(1) << format::significand_bits));
    }

    /* Various boolean observer functions */

    static constexpr bool is_nonzero(carrier_uint u) noexcept { return u << 1; }
    static constexpr bool is_positive(carrier_uint u) noexcept
    {
        return u < (static_cast<carrier_uint>(1) << (format::significand_bits + format::exponent_bits));
    }
    static constexpr bool is_negative(carrier_uint u) noexcept { return !is_positive(u); }
    static constexpr bool is_finite(unsigned exponent_bits) noexcept
    {
        return exponent_bits != ((1u << format::exponent_bits) - 1);
    }
    static constexpr bool has_all_zero_significand_bits(carrier_uint u) noexcept
    {
        return !(u << 1);
    }
    static constexpr bool has_even_significand_bits(carrier_uint u) noexcept
    {
        return !(u % 2);
    }
};

// Convenient wrappers for floating-point traits classes.
// In order to reduce the argument passing overhead, these classes should be as simple as
// possible (e.g., no inheritance, no private non-static data member, etc.; this is an
// unfortunate fact about common ABI convention).

template<class T, class Traits = default_float_traits<T>>
struct float_bits;

template<class T, class Traits = default_float_traits<T>>
struct signed_significand_bits;

template<class T, class Traits>
struct float_bits {
    using type = T;
    using traits_type = Traits;
    using carrier_uint = typename traits_type::carrier_uint;

    carrier_uint u;

    float_bits() = default;
    constexpr explicit float_bits(carrier_uint bit_pattern) noexcept
        : u { bit_pattern }
    {
    }

    constexpr explicit float_bits(T float_value) noexcept
        : u { traits_type::float_to_carrier(float_value) }
    {
    }

    constexpr T to_float() const noexcept { return traits_type::carrier_to_float(u); }

    // Extract exponent bits from a bit pattern.
    // The result must be aligned to the LSB so that there is no additional zero paddings
    // on the right. This function does not do bias adjustment.
    constexpr unsigned extract_exponent_bits() const noexcept
    {
        return traits_type::extract_exponent_bits(u);
    }

    // Extract significand bits from a bit pattern.
    // The result must be aligned to the LSB so that there is no additional zero paddings
    // on the right. The result does not contain the implicit bit.
    constexpr carrier_uint extract_significand_bits() const noexcept
    {
        return traits_type::extract_significand_bits(u);
    }

    // Remove the exponent bits and extract significand bits together with the sign bit.
    constexpr signed_significand_bits<type, traits_type>
    remove_exponent_bits(unsigned exponent_bits) const noexcept
    {
        return signed_significand_bits<type, traits_type>(traits_type::remove_exponent_bits(u, exponent_bits));
    }

    // Obtain the actual value of the binary exponent from the extracted exponent bits.
    static constexpr int32_t binary_exponent(unsigned exponent_bits) noexcept
    {
        return traits_type::binary_exponent(exponent_bits);
    }
    constexpr int32_t binary_exponent() const noexcept
    {
        return binary_exponent(extract_exponent_bits());
    }

    // Obtain the actual value of the binary exponent from the extracted significand bits
    // and exponent bits.
    static constexpr carrier_uint binary_significand(carrier_uint significand_bits, unsigned exponent_bits) noexcept
    {
        return traits_type::binary_significand(significand_bits, exponent_bits);
    }
    constexpr carrier_uint binary_significand() const noexcept
    {
        return binary_significand(extract_significand_bits(), extract_exponent_bits());
    }

    constexpr bool is_nonzero() const noexcept { return traits_type::is_nonzero(u); }
    constexpr bool is_positive() const noexcept { return traits_type::is_positive(u); }
    constexpr bool is_negative() const noexcept { return traits_type::is_negative(u); }
    constexpr bool is_finite(unsigned exponent_bits) const noexcept
    {
        return traits_type::is_finite(exponent_bits);
    }
    constexpr bool is_finite() const noexcept
    {
        return traits_type::is_finite(extract_exponent_bits());
    }
    constexpr bool has_even_significand_bits() const noexcept
    {
        return traits_type::has_even_significand_bits(u);
    }
};

template<class T, class Traits>
struct signed_significand_bits {
    using type = T;
    using traits_type = Traits;
    using carrier_uint = typename traits_type::carrier_uint;

    carrier_uint u;

    signed_significand_bits() = default;
    constexpr explicit signed_significand_bits(carrier_uint bit_pattern) noexcept
        : u { bit_pattern }
    {
    }

    // Shift the obtained signed significand bits to the left by 1 to remove the sign bit.
    constexpr carrier_uint remove_sign_bit_and_shift() const noexcept
    {
        return traits_type::remove_sign_bit_and_shift(u);
    }

    constexpr bool is_positive() const noexcept { return traits_type::is_positive(u); }
    constexpr bool is_negative() const noexcept { return traits_type::is_negative(u); }
    constexpr bool has_all_zero_significand_bits() const noexcept
    {
        return traits_type::has_all_zero_significand_bits(u);
    }
    constexpr bool has_even_significand_bits() const noexcept
    {
        return traits_type::has_even_significand_bits(u);
    }
};

} // namespace dragonbox

} // namespace WTF