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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
|
//===-- Utilities to convert floating point values to string ----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC_SUPPORT_FLOAT_TO_STRING_H
#define LLVM_LIBC_SRC_SUPPORT_FLOAT_TO_STRING_H
#include <stdint.h>
#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/UInt.h"
#include "src/__support/common.h"
#include "src/__support/libc_assert.h"
#include "src/__support/ryu_constants.h"
// This implementation is based on the Ryu Printf algorithm by Ulf Adams:
// Ulf Adams. 2019. Ryƫ revisited: printf floating point conversion.
// Proc. ACM Program. Lang. 3, OOPSLA, Article 169 (October 2019), 23 pages.
// https://doi.org/10.1145/3360595
// This version is modified to require significantly less memory (it doesn't use
// a large buffer to store the result).
// The general concept of this algorithm is as follows:
// We want to calculate a 9 digit segment of a floating point number using this
// formula: floor((mantissa * 2^exponent)/10^i) % 10^9.
// To do so normally would involve large integers (~1000 bits for doubles), so
// we use a shortcut. We can avoid calculating 2^exponent / 10^i by using a
// lookup table. The resulting intermediate value needs to be about 192 bits to
// store the result with enough precision. Since this is all being done with
// integers for appropriate precision, we would run into a problem if
// i > exponent since then 2^exponent / 10^i would be less than 1. To correct
// for this, the actual calculation done is 2^(exponent + c) / 10^i, and then
// when multiplying by the mantissa we reverse this by dividing by 2^c, like so:
// floor((mantissa * table[exponent][i])/(2^c)) % 10^9.
// This gives a 9 digit value, which is small enough to fit in a 32 bit integer,
// and that integer is converted into a string as normal, and called a block. In
// this implementation, the most recent block is buffered, so that if rounding
// is necessary the block can be adjusted before being written to the output.
// Any block that is all 9s adds one to the max block counter and doesn't clear
// the buffer because they can cause the block above them to be rounded up.
namespace __llvm_libc {
using BlockInt = uint32_t;
constexpr size_t BLOCK_SIZE = 9;
using MantissaInt = fputil::FPBits<long double>::UIntType;
constexpr size_t POW10_ADDITIONAL_BITS_CALC = 128;
constexpr size_t POW10_ADDITIONAL_BITS_TABLE = 120;
constexpr size_t MID_INT_SIZE = 192;
namespace internal {
// Returns floor(log_10(2^e)); requires 0 <= e <= 1650.
LIBC_INLINE constexpr uint32_t log10_pow2(const uint32_t e) {
// The first value this approximation fails for is 2^1651 which is just
// greater than 10^297.
LIBC_ASSERT(e >= 0 && e <= 1650 &&
"Incorrect exponent to perform log10_pow2 approximation.");
return (e * 78913) >> 18;
}
// Returns 1 + floor(log_10(2^e). This could technically be off by 1 if any
// power of 2 was also a power of 10, but since that doesn't exist this is
// always accurate. This is used to calculate the maximum number of base-10
// digits a given e-bit number could have.
LIBC_INLINE constexpr uint32_t ceil_log10_pow2(const uint32_t e) {
return log10_pow2(e) + 1;
}
// Returns the maximum number of 9 digit blocks a number described by the given
// index (which is ceil(exponent/16)) and mantissa width could need.
LIBC_INLINE constexpr uint32_t length_for_num(const uint32_t idx,
const uint32_t mantissa_width) {
//+8 to round up when dividing by 9
return (ceil_log10_pow2(16 * idx) + ceil_log10_pow2(mantissa_width) +
(BLOCK_SIZE - 1)) /
BLOCK_SIZE;
// return (ceil_log10_pow2(16 * idx + mantissa_width) + 8) / 9;
}
// The formula for the table when i is positive (or zero) is as follows:
// floor(10^(-9i) * 2^(e + c_1) + 1) % (10^9 * 2^c_1)
// Rewritten slightly we get:
// floor(5^(-9i) * 2^(e + c_1 - 9i) + 1) % (10^9 * 2^c_1)
// TODO: Fix long doubles (needs bigger table or alternate algorithm.)
// Currently the table values are generated, which is very slow.
template <size_t INT_SIZE>
LIBC_INLINE constexpr cpp::UInt<MID_INT_SIZE>
get_table_positive(int exponent, size_t i, const size_t constant) {
// INT_SIZE is the size of int that is used for the internal calculations of
// this function. It should be large enough to hold 2^(exponent+constant), so
// ~1000 for double and ~16000 for long double. Be warned that the time
// complexity of exponentiation is O(n^2 * log_2(m)) where n is the number of
// bits in the number being exponentiated and m is the exponent.
int shift_amount = exponent + constant - (9 * i);
if (shift_amount < 0) {
return 1;
}
cpp::UInt<INT_SIZE> num(0);
// MOD_SIZE is one of the limiting factors for how big the constant argument
// can get, since it needs to be small enough to fit in the result UInt,
// otherwise we'll get truncation on return.
const cpp::UInt<INT_SIZE> MOD_SIZE =
(cpp::UInt<INT_SIZE>(1) << constant) * 1000000000;
constexpr uint64_t FIVE_EXP_NINE = 1953125;
num = cpp::UInt<INT_SIZE>(1) << (shift_amount);
if (i > 0) {
cpp::UInt<INT_SIZE> fives(FIVE_EXP_NINE);
fives.pow_n(i);
num = num / fives;
}
num = num + 1;
if (num > MOD_SIZE) {
num = num % MOD_SIZE;
}
return num;
}
// The formula for the table when i is negative (or zero) is as follows:
// floor(10^(-9i) * 2^(c_0 - e)) % (10^9 * 2^c_0)
// Since we know i is always negative, we just take it as unsigned and treat it
// as negative. We do the same with exponent, while they're both always negative
// in theory, in practice they're converted to positive for simpler
// calculations.
// The formula being used looks more like this:
// floor(10^(9*(-i)) * 2^(c_0 + (-e))) % (10^9 * 2^c_0)
LIBC_INLINE cpp::UInt<MID_INT_SIZE> get_table_negative(int exponent, size_t i,
const size_t constant) {
constexpr size_t INT_SIZE = 1024;
int shift_amount = constant - exponent;
cpp::UInt<INT_SIZE> num(1);
// const cpp::UInt<INT_SIZE> MOD_SIZE =
// (cpp::UInt<INT_SIZE>(1) << constant) * 1000000000;
constexpr uint64_t TEN_EXP_NINE = 1000000000;
constexpr uint64_t FIVE_EXP_NINE = 1953125;
size_t ten_blocks = i;
size_t five_blocks = 0;
if (shift_amount < 0) {
int block_shifts = (-shift_amount) / 9;
if (block_shifts < static_cast<int>(ten_blocks)) {
ten_blocks = ten_blocks - block_shifts;
five_blocks = block_shifts;
shift_amount = shift_amount + (block_shifts * 9);
} else {
ten_blocks = 0;
five_blocks = i;
shift_amount = shift_amount + (i * 9);
}
}
if (five_blocks > 0) {
cpp::UInt<INT_SIZE> fives(FIVE_EXP_NINE);
fives.pow_n(five_blocks);
num *= fives;
}
if (ten_blocks > 0) {
cpp::UInt<INT_SIZE> tens(TEN_EXP_NINE);
tens.pow_n(ten_blocks);
num *= tens;
}
if (shift_amount > 0) {
num = num << shift_amount;
} else {
num = num >> (-shift_amount);
}
// if (num > MOD_SIZE) {
// num = num % MOD_SIZE;
// }
return num;
}
LIBC_INLINE uint32_t fast_uint_mod_1e9(const cpp::UInt<MID_INT_SIZE> &val) {
// The formula for mult_const is:
// 1 + floor((2^(bits in target integer size + log_2(divider))) / divider)
// Where divider is 10^9 and target integer size is 128.
const cpp::UInt<MID_INT_SIZE> mult_const(
{0x31680A88F8953031u, 0x89705F4136B4A597u, 0});
const auto middle = (mult_const * val);
const uint64_t result = static_cast<uint64_t>(middle[2]);
const uint32_t shifted = result >> 29;
return static_cast<uint32_t>(val) - (1000000000 * shifted);
}
LIBC_INLINE uint32_t mul_shift_mod_1e9(const MantissaInt mantissa,
const cpp::UInt<MID_INT_SIZE> &large,
const int32_t shift_amount) {
constexpr size_t MANT_INT_SIZE = sizeof(MantissaInt) * 8;
cpp::UInt<MID_INT_SIZE + MANT_INT_SIZE> val(large);
// TODO: Find a better way to force __uint128_t to be UInt<128>
cpp::UInt<MANT_INT_SIZE> wide_mant(0);
wide_mant[0] = mantissa & (uint64_t(-1));
wide_mant[1] = mantissa >> 64;
val = (val * wide_mant) >> shift_amount;
return fast_uint_mod_1e9(val);
}
} // namespace internal
// Convert floating point values to their string representation.
// Because the result may not fit in a reasonably sized array, the caller must
// request blocks of digits and convert them from integers to strings themself.
// Blocks contain the most digits that can be stored in an BlockInt. This is 9
// digits for a 32 bit int and 18 digits for a 64 bit int.
// The intended use pattern is to create a FloatToString object of the
// appropriate type, then call get_positive_blocks to get an approximate number
// of blocks there are before the decimal point. Now the client code can start
// calling get_positive_block in a loop from the number of positive blocks to
// zero. This will give all digits before the decimal point. Then the user can
// start calling get_negative_block in a loop from 0 until the number of digits
// they need is reached. As an optimization, the client can use
// zero_blocks_after_point to find the number of blocks that are guaranteed to
// be zero after the decimal point and before the non-zero digits. Additionally,
// is_lowest_block will return if the current block is the lowest non-zero
// block.
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
class FloatToString {
fputil::FPBits<T> float_bits;
bool is_negative;
int exponent;
MantissaInt mantissa;
static constexpr int MANT_WIDTH = fputil::MantissaWidth<T>::VALUE;
static constexpr int EXP_BIAS = fputil::FPBits<T>::EXPONENT_BIAS;
// constexpr void init_convert();
public:
LIBC_INLINE constexpr FloatToString(T init_float) : float_bits(init_float) {
is_negative = float_bits.get_sign();
exponent = float_bits.get_exponent();
mantissa = float_bits.get_explicit_mantissa();
// Handle the exponent for numbers with a 0 exponent.
if (exponent == -EXP_BIAS) {
if (mantissa > 0) { // Subnormals
++exponent;
} else { // Zeroes
exponent = 0;
}
}
// Adjust for the width of the mantissa.
exponent -= MANT_WIDTH;
// init_convert();
}
LIBC_INLINE constexpr bool is_nan() { return float_bits.is_nan(); }
LIBC_INLINE constexpr bool is_inf() { return float_bits.is_inf(); }
LIBC_INLINE constexpr bool is_inf_or_nan() {
return float_bits.is_inf_or_nan();
}
// get_block returns an integer that represents the digits in the requested
// block.
LIBC_INLINE constexpr BlockInt get_positive_block(int block_index) {
if (exponent >= -MANT_WIDTH) {
// idx is ceil(exponent/16) or 0 if exponent is negative. This is used to
// find the coarse section of the POW10_SPLIT table that will be used to
// calculate the 9 digit window, as well as some other related values.
const uint32_t idx =
exponent < 0 ? 0 : static_cast<uint32_t>(exponent + 15) / 16;
uint32_t temp_shift_amount =
POW10_ADDITIONAL_BITS_TABLE + (16 * idx) - exponent;
const uint32_t shift_amount = temp_shift_amount;
// shift_amount = -(c0 - exponent) = c_0 + 16 * ceil(exponent/16) -
// exponent
int32_t i = block_index;
cpp::UInt<MID_INT_SIZE> val;
val = POW10_SPLIT[POW10_OFFSET[idx] + i];
const uint32_t digits =
internal::mul_shift_mod_1e9(mantissa, val, (int32_t)(shift_amount));
return digits;
} else {
return 0;
}
}
LIBC_INLINE constexpr BlockInt get_negative_block(int block_index) {
if (exponent < 0) {
const int32_t idx = -exponent / 16;
uint32_t i = block_index;
// if the requested block is zero
if (i < MIN_BLOCK_2[idx]) {
return 0;
}
const int32_t shift_amount =
POW10_ADDITIONAL_BITS_TABLE + (-exponent - 16 * idx);
const uint32_t p = POW10_OFFSET_2[idx] + i - MIN_BLOCK_2[idx];
// If every digit after the requested block is zero.
if (p >= POW10_OFFSET_2[idx + 1]) {
return 0;
}
cpp::UInt<MID_INT_SIZE> table_val = POW10_SPLIT_2[p];
// cpp::UInt<MID_INT_SIZE> calculated_val =
// get_table_negative(idx * 16, i + 1, POW10_ADDITIONAL_BITS_CALC);
uint32_t digits =
internal::mul_shift_mod_1e9(mantissa, table_val, shift_amount);
return digits;
} else {
return 0;
}
}
LIBC_INLINE constexpr BlockInt get_block(int block_index) {
if (block_index >= 0) {
return get_positive_block(block_index);
} else {
return get_negative_block(-1 - block_index);
}
}
LIBC_INLINE constexpr size_t get_positive_blocks() {
if (exponent >= -MANT_WIDTH) {
const uint32_t idx =
exponent < 0 ? 0 : static_cast<uint32_t>(exponent + 15) / 16;
const uint32_t len = internal::length_for_num(idx, MANT_WIDTH);
return len;
} else {
return 0;
}
}
// This takes the index of a block after the decimal point (a negative block)
// and return if it's sure that all of the digits after it are zero.
LIBC_INLINE constexpr bool is_lowest_block(size_t block_index) {
const int32_t idx = -exponent / 16;
const uint32_t p = POW10_OFFSET_2[idx] + block_index - MIN_BLOCK_2[idx];
// If the remaining digits are all 0, then this is the lowest block.
return p >= POW10_OFFSET_2[idx + 1];
}
LIBC_INLINE constexpr size_t zero_blocks_after_point() {
return MIN_BLOCK_2[-exponent / 16];
}
};
// template <> constexpr void FloatToString<float>::init_convert() { ; }
// template <> constexpr void FloatToString<double>::init_convert() { ; }
// template <> constexpr void FloatToString<long double>::init_convert() {
// // TODO: More here.
// ;
// }
template <>
LIBC_INLINE constexpr size_t
FloatToString<long double>::zero_blocks_after_point() {
return 0;
}
template <>
LIBC_INLINE constexpr bool FloatToString<long double>::is_lowest_block(size_t) {
return false;
}
template <>
LIBC_INLINE constexpr BlockInt
FloatToString<long double>::get_positive_block(int block_index) {
if (exponent >= -MANT_WIDTH) {
const uint32_t pos_exp = (exponent < 0 ? 0 : exponent);
uint32_t temp_shift_amount =
POW10_ADDITIONAL_BITS_CALC + pos_exp - exponent;
const uint32_t shift_amount = temp_shift_amount;
// shift_amount = -(c0 - exponent) = c_0 + 16 * ceil(exponent/16) -
// exponent
int32_t i = block_index;
cpp::UInt<MID_INT_SIZE> val;
if (exponent + POW10_ADDITIONAL_BITS_CALC < 1024) {
val = internal::get_table_positive<1024>(pos_exp, i,
POW10_ADDITIONAL_BITS_CALC);
} else if (exponent + POW10_ADDITIONAL_BITS_CALC < 4096) {
val = internal::get_table_positive<4096>(pos_exp, i,
POW10_ADDITIONAL_BITS_CALC);
} else if (exponent + POW10_ADDITIONAL_BITS_CALC < 8192) {
val = internal::get_table_positive<8192>(pos_exp, i,
POW10_ADDITIONAL_BITS_CALC);
} else {
val = internal::get_table_positive<16384>(pos_exp, i,
POW10_ADDITIONAL_BITS_CALC);
}
const BlockInt digits =
internal::mul_shift_mod_1e9(mantissa, val, (int32_t)(shift_amount));
return digits;
} else {
return 0;
}
}
template <>
LIBC_INLINE constexpr BlockInt
FloatToString<long double>::get_negative_block(int block_index) {
if (exponent < 0) {
const int32_t idx = -exponent / 16;
uint32_t i = -1 - block_index;
// if the requested block is zero
if (i <= MIN_BLOCK_2[idx]) {
return 0;
}
const int32_t shift_amount =
POW10_ADDITIONAL_BITS_CALC + (-exponent - 16 * idx);
const uint32_t p = POW10_OFFSET_2[idx] + i - MIN_BLOCK_2[idx];
// If every digit after the requested block is zero.
if (p >= POW10_OFFSET_2[idx + 1]) {
return 0;
}
// cpp::UInt<MID_INT_SIZE> table_val = POW10_SPLIT_2[p];
cpp::UInt<MID_INT_SIZE> calculated_val = internal::get_table_negative(
idx * 16, i + 1, POW10_ADDITIONAL_BITS_CALC);
BlockInt digits =
internal::mul_shift_mod_1e9(mantissa, calculated_val, shift_amount);
return digits;
} else {
return 0;
}
}
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_SUPPORT_FLOAT_TO_STRING_H
|