mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-24 14:20:17 +00:00
[libc] add options to printf decimal floats
This patch adds three options for printf decimal long doubles, and these can also apply to doubles. 1. Use a giant table which is fast and accurate, but takes up ~5MB). 2. Use dyadic floats for approximations, which only gives ~50 digits of accuracy but is very fast. 3. Use large integers for approximations, which is accurate but very slow. Reviewed By: sivachandra, lntue Differential Revision: https://reviews.llvm.org/D150399
This commit is contained in:
parent
086183c6c6
commit
688b9730d1
@ -102,6 +102,7 @@ add_header_library(
|
||||
HDRS
|
||||
float_to_string.h
|
||||
ryu_constants.h
|
||||
ryu_long_double_constants.h
|
||||
DEPENDS
|
||||
.libc_assert
|
||||
libc.src.__support.CPP.type_traits
|
||||
|
@ -52,14 +52,14 @@ template <size_t Bits> struct DyadicFloat {
|
||||
normalize();
|
||||
}
|
||||
|
||||
DyadicFloat(bool s, int e, MantissaType m)
|
||||
constexpr DyadicFloat(bool s, int e, MantissaType m)
|
||||
: sign(s), exponent(e), mantissa(m) {
|
||||
normalize();
|
||||
}
|
||||
|
||||
// Normalizing the mantissa, bringing the leading 1 bit to the most
|
||||
// significant bit.
|
||||
DyadicFloat &normalize() {
|
||||
constexpr DyadicFloat &normalize() {
|
||||
if (!mantissa.is_zero()) {
|
||||
int shift_length = static_cast<int>(mantissa.clz());
|
||||
exponent -= shift_length;
|
||||
@ -118,6 +118,24 @@ template <size_t Bits> struct DyadicFloat {
|
||||
// Still correct without FMA instructions if `d_lo` is not underflow.
|
||||
return multiply_add(d_lo.get_val(), T(round_and_sticky), d_hi.get_val());
|
||||
}
|
||||
|
||||
explicit operator MantissaType() const {
|
||||
if (mantissa.is_zero())
|
||||
return 0;
|
||||
|
||||
MantissaType new_mant = mantissa;
|
||||
if (exponent > 0) {
|
||||
new_mant <<= exponent;
|
||||
} else {
|
||||
new_mant >>= (-exponent);
|
||||
}
|
||||
|
||||
if (sign) {
|
||||
new_mant = (~new_mant) + 1;
|
||||
}
|
||||
|
||||
return new_mant;
|
||||
}
|
||||
};
|
||||
|
||||
// Quick add - Add 2 dyadic floats with rounding toward 0 and then normalize the
|
||||
@ -208,6 +226,30 @@ constexpr DyadicFloat<Bits> quick_mul(DyadicFloat<Bits> a,
|
||||
return result;
|
||||
}
|
||||
|
||||
// Simple exponentiation implementation for printf. Only handles positive
|
||||
// exponents, since division isn't implemented.
|
||||
template <size_t Bits>
|
||||
constexpr DyadicFloat<Bits> pow_n(DyadicFloat<Bits> a, uint32_t power) {
|
||||
DyadicFloat<Bits> result = 1.0;
|
||||
DyadicFloat<Bits> cur_power = a;
|
||||
|
||||
while (power > 0) {
|
||||
if ((power % 2) > 0) {
|
||||
result = quick_mul(result, cur_power);
|
||||
}
|
||||
power = power >> 1;
|
||||
cur_power = quick_mul(cur_power, cur_power);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <size_t Bits>
|
||||
constexpr DyadicFloat<Bits> mul_pow_2(DyadicFloat<Bits> a, int32_t pow_2) {
|
||||
DyadicFloat<Bits> result = a;
|
||||
result.exponent += pow_2;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc::fputil
|
||||
|
||||
#endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_DYADIC_FLOAT_H
|
||||
|
@ -13,10 +13,65 @@
|
||||
|
||||
#include "src/__support/CPP/type_traits.h"
|
||||
#include "src/__support/FPUtil/FPBits.h"
|
||||
#include "src/__support/FPUtil/dyadic_float.h"
|
||||
#include "src/__support/UInt.h"
|
||||
#include "src/__support/common.h"
|
||||
#include "src/__support/libc_assert.h"
|
||||
|
||||
// This file has 5 compile-time flags to allow the user to configure the float
|
||||
// to string behavior. These allow the user to select which 2 of the 3 useful
|
||||
// properties they want. The useful properties are:
|
||||
// 1) Speed of Evaluation
|
||||
// 2) Small Size of Binary
|
||||
// 3) Centered Output Value
|
||||
// These are explained below with the flags that are missing each one.
|
||||
|
||||
// LIBC_COPT_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE
|
||||
// The Mega Table is ~5 megabytes when compiled. It lists the constants needed
|
||||
// to perform the Ryu Printf algorithm (described below) for all long double
|
||||
// values. This makes it extremely fast for both doubles and long doubles, in
|
||||
// exchange for large binary size.
|
||||
|
||||
// LIBC_COPT_FLOAT_TO_STR_USE_DYADIC_FLOAT
|
||||
// LIBC_COPT_FLOAT_TO_STR_USE_DYADIC_FLOAT_LD
|
||||
// Dyadic floats are software floating point numbers, and their accuracy can be
|
||||
// as high as necessary. This option uses 256 bit dyadic floats to calculate
|
||||
// the table values that Ryu Printf needs. This is reasonably fast and very
|
||||
// small compared to the Mega Table, but the 256 bit floats only give accurate
|
||||
// results for the first ~50 digits of the output. In practice this shouldn't
|
||||
// be a problem since long doubles are only accurate for ~35 digits, but the
|
||||
// trailing values all being 0s may cause brittle tests to fail. The _LD
|
||||
// version of this flag only effects the long double calculations, and the
|
||||
// other version effects both long double and double.
|
||||
|
||||
// LIBC_COPT_FLOAT_TO_STR_USE_INT_CALC
|
||||
// Integer Calculation uses wide integers to do the calculations for the Ryu
|
||||
// Printf table, which is just as accurate as the Mega Table without requiring
|
||||
// as much code size. These integers can be very large (~32KB at max, though
|
||||
// always on the stack) to handle the edges of the long double range. They are
|
||||
// also very slow, taking multiple seconds on a powerful CPU to calculate the
|
||||
// values at the end of the range. If no flag is set, this is used for long
|
||||
// doubles, the flag only changes the double behavior.
|
||||
|
||||
// LIBC_COPT_FLOAT_TO_STR_NO_TABLE
|
||||
// This flag doesn't change the actual calculation method, instead it is used
|
||||
// to disable the normal Ryu Printf table for configurations that don't use any
|
||||
// table at all.
|
||||
|
||||
// Default Config:
|
||||
// If no flags are set, doubles use the normal (and much more reasonably sized)
|
||||
// Ryu Printf table and long doubles use Integer Calculation. This is because
|
||||
// long doubles are rarely used and the normal Ryu Printf table is very fast
|
||||
// for doubles.
|
||||
|
||||
#ifdef LIBC_COPT_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE
|
||||
#include "src/__support/ryu_long_double_constants.h"
|
||||
#elif !defined(LIBC_COPT_FLOAT_TO_STR_NO_TABLE)
|
||||
#include "src/__support/ryu_constants.h"
|
||||
#else
|
||||
constexpr size_t IDX_SIZE = 1;
|
||||
constexpr size_t MID_INT_SIZE = 192;
|
||||
#endif
|
||||
|
||||
// This implementation is based on the Ryu Printf algorithm by Ulf Adams:
|
||||
// Ulf Adams. 2019. Ryū revisited: printf floating point conversion.
|
||||
@ -52,20 +107,41 @@ 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;
|
||||
// Larger numbers prefer a slightly larger constant than is used for the smaller
|
||||
// numbers.
|
||||
constexpr size_t CALC_SHIFT_CONST = 128;
|
||||
|
||||
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 &&
|
||||
// Returns floor(log_10(2^e)); requires 0 <= e <= 42039.
|
||||
LIBC_INLINE constexpr uint32_t log10_pow2(const uint64_t e) {
|
||||
LIBC_ASSERT(e >= 0 && e <= 42039 &&
|
||||
"Incorrect exponent to perform log10_pow2 approximation.");
|
||||
return (e * 78913) >> 18;
|
||||
// This approximation is based on the float value for log_10(2). It first
|
||||
// gives an incorrect result for our purposes at 42039 (well beyond the 16383
|
||||
// maximum for long doubles).
|
||||
|
||||
// To get these constants I first evaluated log_10(2) to get an approximation
|
||||
// of 0.301029996. Next I passed that value through a string to double
|
||||
// conversion to get an explicit mantissa of 0x13441350fbd738 and an exponent
|
||||
// of -2 (which becomes -54 when we shift the mantissa to be a non-fractional
|
||||
// number). Next I shifted the mantissa right 12 bits to create more space for
|
||||
// the multiplication result, adding 12 to the exponent to compensate. To
|
||||
// check that this approximation works for our purposes I used the following
|
||||
// python code:
|
||||
// for i in range(16384):
|
||||
// if(len(str(2**i)) != (((i*0x13441350fbd)>>42)+1)):
|
||||
// print(i)
|
||||
// The reason we add 1 is because this evaluation truncates the result, giving
|
||||
// us the floor, whereas counting the digits of the power of 2 gives us the
|
||||
// ceiling. With a similar loop I checked the maximum valid value and found
|
||||
// 42039.
|
||||
return (e * 0x13441350fbdll) >> 42;
|
||||
}
|
||||
|
||||
// Same as above, but with different constants.
|
||||
LIBC_INLINE constexpr uint32_t log2_pow5(const uint64_t e) {
|
||||
return (e * 0x12934f0979bll) >> 39;
|
||||
}
|
||||
|
||||
// Returns 1 + floor(log_10(2^e). This could technically be off by 1 if any
|
||||
@ -81,7 +157,7 @@ LIBC_INLINE constexpr uint32_t ceil_log10_pow2(const uint32_t e) {
|
||||
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) +
|
||||
return (ceil_log10_pow2(idx) + ceil_log10_pow2(mantissa_width) +
|
||||
(BLOCK_SIZE - 1)) /
|
||||
BLOCK_SIZE;
|
||||
// return (ceil_log10_pow2(16 * idx + mantissa_width) + 8) / 9;
|
||||
@ -95,14 +171,14 @@ LIBC_INLINE constexpr uint32_t length_for_num(const uint32_t idx,
|
||||
// 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) {
|
||||
LIBC_INLINE constexpr cpp::UInt<MID_INT_SIZE> get_table_positive(int exponent,
|
||||
size_t i) {
|
||||
// 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);
|
||||
const int shift_amount = exponent + CALC_SHIFT_CONST - (BLOCK_SIZE * i);
|
||||
if (shift_amount < 0) {
|
||||
return 1;
|
||||
}
|
||||
@ -110,8 +186,10 @@ get_table_positive(int exponent, size_t i, const size_t constant) {
|
||||
// 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 cpp::UInt<INT_SIZE> MOD_SIZE =
|
||||
(cpp::UInt<INT_SIZE>(1000000000)
|
||||
<< (CALC_SHIFT_CONST + (IDX_SIZE > 1 ? IDX_SIZE : 0)));
|
||||
|
||||
constexpr uint64_t FIVE_EXP_NINE = 1953125;
|
||||
|
||||
num = cpp::UInt<INT_SIZE>(1) << (shift_amount);
|
||||
@ -123,11 +201,64 @@ get_table_positive(int exponent, size_t i, const size_t constant) {
|
||||
|
||||
num = num + 1;
|
||||
if (num > MOD_SIZE) {
|
||||
num = num % MOD_SIZE;
|
||||
auto rem =
|
||||
num.div_uint32_times_pow_2(
|
||||
1000000000, CALC_SHIFT_CONST + (IDX_SIZE > 1 ? IDX_SIZE : 0))
|
||||
.value();
|
||||
num = rem;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
template <size_t INT_SIZE>
|
||||
LIBC_INLINE cpp::UInt<MID_INT_SIZE> get_table_positive_df(int exponent,
|
||||
size_t i) {
|
||||
static_assert(INT_SIZE == 256,
|
||||
"Only 256 is supported as an int size right now.");
|
||||
// This version uses dyadic floats with 256 bit mantissas to perform the same
|
||||
// calculation as above. Due to floating point imprecision it is only accurate
|
||||
// for the first 50 digits, but it's much faster. Since even 128 bit long
|
||||
// doubles are only accurate to ~35 digits, the 50 digits of accuracy are
|
||||
// enough for these floats to be converted back and forth safely. This is
|
||||
// ideal for avoiding the size of the long double table.
|
||||
const int shift_amount = exponent + CALC_SHIFT_CONST - (9 * i);
|
||||
if (shift_amount < 0) {
|
||||
return 1;
|
||||
}
|
||||
fputil::DyadicFloat<INT_SIZE> num(false, 0, 1);
|
||||
constexpr cpp::UInt<INT_SIZE> MOD_SIZE =
|
||||
(cpp::UInt<INT_SIZE>(1000000000)
|
||||
<< (CALC_SHIFT_CONST + (IDX_SIZE > 1 ? IDX_SIZE : 0)));
|
||||
|
||||
constexpr cpp::UInt<INT_SIZE> FIVE_EXP_MINUS_NINE_MANT{
|
||||
{0xf387295d242602a7, 0xfdd7645e011abac9, 0x31680a88f8953030,
|
||||
0x89705f4136b4a597}};
|
||||
|
||||
static const fputil::DyadicFloat<INT_SIZE> FIVE_EXP_MINUS_NINE(
|
||||
false, -276, FIVE_EXP_MINUS_NINE_MANT);
|
||||
|
||||
if (i > 0) {
|
||||
fputil::DyadicFloat<INT_SIZE> fives = fputil::pow_n(FIVE_EXP_MINUS_NINE, i);
|
||||
num = fives;
|
||||
}
|
||||
num = mul_pow_2(num, shift_amount);
|
||||
|
||||
// Adding one is part of the formula.
|
||||
cpp::UInt<INT_SIZE> int_num = static_cast<cpp::UInt<INT_SIZE>>(num) + 1;
|
||||
if (int_num > MOD_SIZE) {
|
||||
auto rem =
|
||||
int_num
|
||||
.div_uint32_times_pow_2(
|
||||
1000000000, CALC_SHIFT_CONST + (IDX_SIZE > 1 ? IDX_SIZE : 0))
|
||||
.value();
|
||||
int_num = rem;
|
||||
}
|
||||
|
||||
cpp::UInt<MID_INT_SIZE> result = int_num;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -136,40 +267,44 @@ get_table_positive(int exponent, size_t i, const size_t constant) {
|
||||
// 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;
|
||||
template <size_t INT_SIZE>
|
||||
LIBC_INLINE cpp::UInt<MID_INT_SIZE> get_table_negative(int exponent, size_t i) {
|
||||
int shift_amount = CALC_SHIFT_CONST - exponent;
|
||||
cpp::UInt<INT_SIZE> num(1);
|
||||
// const cpp::UInt<INT_SIZE> MOD_SIZE =
|
||||
// (cpp::UInt<INT_SIZE>(1) << constant) * 1000000000;
|
||||
constexpr cpp::UInt<INT_SIZE> MOD_SIZE =
|
||||
(cpp::UInt<INT_SIZE>(1000000000)
|
||||
<< (CALC_SHIFT_CONST + (IDX_SIZE > 1 ? IDX_SIZE : 0)));
|
||||
|
||||
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;
|
||||
int block_shifts = (-shift_amount) / BLOCK_SIZE;
|
||||
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);
|
||||
shift_amount = shift_amount + (block_shifts * BLOCK_SIZE);
|
||||
} else {
|
||||
ten_blocks = 0;
|
||||
five_blocks = i;
|
||||
shift_amount = shift_amount + (i * 9);
|
||||
shift_amount = shift_amount + (i * BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
if (five_blocks > 0) {
|
||||
cpp::UInt<INT_SIZE> fives(FIVE_EXP_NINE);
|
||||
fives.pow_n(five_blocks);
|
||||
num *= fives;
|
||||
num = fives;
|
||||
}
|
||||
if (ten_blocks > 0) {
|
||||
cpp::UInt<INT_SIZE> tens(TEN_EXP_NINE);
|
||||
tens.pow_n(ten_blocks);
|
||||
num *= tens;
|
||||
if (five_blocks <= 0) {
|
||||
num = tens;
|
||||
} else {
|
||||
num *= tens;
|
||||
}
|
||||
}
|
||||
|
||||
if (shift_amount > 0) {
|
||||
@ -177,12 +312,61 @@ LIBC_INLINE cpp::UInt<MID_INT_SIZE> get_table_negative(int exponent, size_t i,
|
||||
} else {
|
||||
num = num >> (-shift_amount);
|
||||
}
|
||||
// if (num > MOD_SIZE) {
|
||||
// num = num % MOD_SIZE;
|
||||
// }
|
||||
if (num > MOD_SIZE) {
|
||||
auto rem =
|
||||
num.div_uint32_times_pow_2(
|
||||
1000000000, CALC_SHIFT_CONST + (IDX_SIZE > 1 ? IDX_SIZE : 0))
|
||||
.value();
|
||||
num = rem;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
template <size_t INT_SIZE>
|
||||
LIBC_INLINE cpp::UInt<MID_INT_SIZE> get_table_negative_df(int exponent,
|
||||
size_t i) {
|
||||
static_assert(INT_SIZE == 256,
|
||||
"Only 256 is supported as an int size right now.");
|
||||
// This version uses dyadic floats with 256 bit mantissas to perform the same
|
||||
// calculation as above. Due to floating point imprecision it is only accurate
|
||||
// for the first 50 digits, but it's much faster. Since even 128 bit long
|
||||
// doubles are only accurate to ~35 digits, the 50 digits of accuracy are
|
||||
// enough for these floats to be converted back and forth safely. This is
|
||||
// ideal for avoiding the size of the long double table.
|
||||
|
||||
int shift_amount = CALC_SHIFT_CONST - exponent;
|
||||
|
||||
fputil::DyadicFloat<INT_SIZE> num(false, 0, 1);
|
||||
constexpr cpp::UInt<INT_SIZE> MOD_SIZE =
|
||||
(cpp::UInt<INT_SIZE>(1000000000)
|
||||
<< (CALC_SHIFT_CONST + (IDX_SIZE > 1 ? IDX_SIZE : 0)));
|
||||
|
||||
constexpr cpp::UInt<INT_SIZE> TEN_EXP_NINE_MANT(1000000000);
|
||||
|
||||
static const fputil::DyadicFloat<INT_SIZE> TEN_EXP_NINE(false, 0,
|
||||
TEN_EXP_NINE_MANT);
|
||||
|
||||
if (i > 0) {
|
||||
fputil::DyadicFloat<INT_SIZE> tens = fputil::pow_n(TEN_EXP_NINE, i);
|
||||
num = tens;
|
||||
}
|
||||
num = mul_pow_2(num, shift_amount);
|
||||
|
||||
cpp::UInt<INT_SIZE> int_num = static_cast<cpp::UInt<INT_SIZE>>(num);
|
||||
if (int_num > MOD_SIZE) {
|
||||
auto rem =
|
||||
int_num
|
||||
.div_uint32_times_pow_2(
|
||||
1000000000, CALC_SHIFT_CONST + (IDX_SIZE > 1 ? IDX_SIZE : 0))
|
||||
.value();
|
||||
int_num = rem;
|
||||
}
|
||||
|
||||
cpp::UInt<MID_INT_SIZE> result = int_num;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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)
|
||||
@ -205,7 +389,9 @@ LIBC_INLINE uint32_t mul_shift_mod_1e9(const MantissaInt mantissa,
|
||||
wide_mant[0] = mantissa & (uint64_t(-1));
|
||||
wide_mant[1] = mantissa >> 64;
|
||||
val = (val * wide_mant) >> shift_amount;
|
||||
return fast_uint_mod_1e9(val);
|
||||
|
||||
return val.div_uint32_times_pow_2(1000000000, 0).value()[0];
|
||||
// return fast_uint_mod_1e9(val);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
@ -236,8 +422,6 @@ class FloatToString {
|
||||
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();
|
||||
@ -273,18 +457,49 @@ public:
|
||||
// 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;
|
||||
exponent < 0
|
||||
? 0
|
||||
: static_cast<uint32_t>(exponent + (IDX_SIZE - 1)) / IDX_SIZE;
|
||||
|
||||
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];
|
||||
|
||||
#if defined(LIBC_COPT_FLOAT_TO_STR_USE_DYADIC_FLOAT)
|
||||
// ----------------------- DYADIC FLOAT CALC MODE ------------------------
|
||||
const int32_t SHIFT_CONST = CALC_SHIFT_CONST;
|
||||
val = internal::get_table_positive_df<256>(IDX_SIZE * idx, block_index);
|
||||
#elif defined(LIBC_COPT_FLOAT_TO_STR_USE_INT_CALC)
|
||||
|
||||
// ---------------------------- INT CALC MODE ----------------------------
|
||||
const int32_t SHIFT_CONST = CALC_SHIFT_CONST;
|
||||
|
||||
const uint64_t MAX_POW_2_SIZE =
|
||||
exponent + CALC_SHIFT_CONST - (BLOCK_SIZE * block_index);
|
||||
const uint64_t MAX_POW_5_SIZE =
|
||||
internal::log2_pow5(BLOCK_SIZE * block_index);
|
||||
const uint64_t MAX_INT_SIZE =
|
||||
(MAX_POW_2_SIZE > MAX_POW_5_SIZE) ? MAX_POW_2_SIZE : MAX_POW_5_SIZE;
|
||||
|
||||
if (MAX_INT_SIZE < 1024) {
|
||||
val = internal::get_table_positive<1024>(IDX_SIZE * idx, block_index);
|
||||
} else if (MAX_INT_SIZE < 2048) {
|
||||
val = internal::get_table_positive<2048>(IDX_SIZE * idx, block_index);
|
||||
} else if (MAX_INT_SIZE < 4096) {
|
||||
val = internal::get_table_positive<4096>(IDX_SIZE * idx, block_index);
|
||||
} else if (MAX_INT_SIZE < 8192) {
|
||||
val = internal::get_table_positive<8192>(IDX_SIZE * idx, block_index);
|
||||
} else {
|
||||
val = internal::get_table_positive<16384>(IDX_SIZE * idx, block_index);
|
||||
}
|
||||
#else
|
||||
// ----------------------------- TABLE MODE ------------------------------
|
||||
const int32_t SHIFT_CONST = TABLE_SHIFT_CONST;
|
||||
|
||||
val = POW10_SPLIT[POW10_OFFSET[idx] + block_index];
|
||||
#endif
|
||||
const uint32_t shift_amount = SHIFT_CONST + (IDX_SIZE * idx) - exponent;
|
||||
const uint32_t digits =
|
||||
internal::mul_shift_mod_1e9(mantissa, val, (int32_t)(shift_amount));
|
||||
return digits;
|
||||
@ -295,25 +510,58 @@ public:
|
||||
|
||||
LIBC_INLINE constexpr BlockInt get_negative_block(int block_index) {
|
||||
if (exponent < 0) {
|
||||
const int32_t idx = -exponent / 16;
|
||||
uint32_t i = block_index;
|
||||
const int32_t idx = -exponent / IDX_SIZE;
|
||||
|
||||
cpp::UInt<MID_INT_SIZE> val;
|
||||
|
||||
#if defined(LIBC_COPT_FLOAT_TO_STR_USE_DYADIC_FLOAT)
|
||||
// ----------------------- DYADIC FLOAT CALC MODE ------------------------
|
||||
const int32_t SHIFT_CONST = CALC_SHIFT_CONST;
|
||||
val =
|
||||
internal::get_table_negative_df<256>(idx * IDX_SIZE, block_index + 1);
|
||||
#elif defined(LIBC_COPT_FLOAT_TO_STR_USE_INT_CALC)
|
||||
// ---------------------------- INT CALC MODE ----------------------------
|
||||
const int32_t SHIFT_CONST = CALC_SHIFT_CONST;
|
||||
const uint64_t TEN_BLOCKS = (block_index + 1) * BLOCK_SIZE;
|
||||
const uint64_t MAX_INT_SIZE = internal::log2_pow5(TEN_BLOCKS);
|
||||
|
||||
if (MAX_INT_SIZE < 1024) {
|
||||
val =
|
||||
internal::get_table_negative<1024>(idx * IDX_SIZE, block_index + 1);
|
||||
} else if (MAX_INT_SIZE < 2048) {
|
||||
val =
|
||||
internal::get_table_negative<2048>(idx * IDX_SIZE, block_index + 1);
|
||||
} else if (MAX_INT_SIZE < 4096) {
|
||||
val =
|
||||
internal::get_table_negative<4096>(idx * IDX_SIZE, block_index + 1);
|
||||
} else if (MAX_INT_SIZE < 8192) {
|
||||
val =
|
||||
internal::get_table_negative<8192>(idx * IDX_SIZE, block_index + 1);
|
||||
} else if (MAX_INT_SIZE < 16384) {
|
||||
val = internal::get_table_negative<16384>(idx * IDX_SIZE,
|
||||
block_index + 1);
|
||||
} else {
|
||||
val = internal::get_table_negative<32768>(idx * IDX_SIZE,
|
||||
block_index + 1);
|
||||
}
|
||||
#else
|
||||
// ----------------------------- TABLE MODE ------------------------------
|
||||
// if the requested block is zero
|
||||
if (i < MIN_BLOCK_2[idx]) {
|
||||
const int32_t SHIFT_CONST = TABLE_SHIFT_CONST;
|
||||
if (block_index < 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];
|
||||
const uint32_t p = POW10_OFFSET_2[idx] + block_index - 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);
|
||||
val = POW10_SPLIT_2[p];
|
||||
#endif
|
||||
const int32_t shift_amount = SHIFT_CONST + (-exponent - IDX_SIZE * idx);
|
||||
uint32_t digits =
|
||||
internal::mul_shift_mod_1e9(mantissa, table_val, shift_amount);
|
||||
internal::mul_shift_mod_1e9(mantissa, val, shift_amount);
|
||||
return digits;
|
||||
} else {
|
||||
return 0;
|
||||
@ -331,8 +579,10 @@ public:
|
||||
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);
|
||||
exponent < 0
|
||||
? 0
|
||||
: static_cast<uint32_t>(exponent + (IDX_SIZE - 1)) / IDX_SIZE;
|
||||
const uint32_t len = internal::length_for_num(idx * IDX_SIZE, MANT_WIDTH);
|
||||
return len;
|
||||
} else {
|
||||
return 0;
|
||||
@ -342,30 +592,53 @@ public:
|
||||
// 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;
|
||||
#ifdef LIBC_COPT_FLOAT_TO_STR_NO_TABLE
|
||||
return false;
|
||||
#else
|
||||
const int32_t idx = -exponent / IDX_SIZE;
|
||||
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];
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr size_t zero_blocks_after_point() {
|
||||
return MIN_BLOCK_2[-exponent / 16];
|
||||
#ifdef LIBC_COPT_FLOAT_TO_STR_NO_TABLE
|
||||
return 0;
|
||||
// TODO (michaelrj): Find a good algorithm for this that doesn't use a
|
||||
// table.
|
||||
#else
|
||||
return MIN_BLOCK_2[-exponent / IDX_SIZE];
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
// template <> constexpr void FloatToString<float>::init_convert() { ; }
|
||||
#ifndef LONG_DOUBLE_IS_DOUBLE
|
||||
// --------------------------- LONG DOUBLE FUNCTIONS ---------------------------
|
||||
|
||||
// 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>::get_positive_blocks() {
|
||||
if (exponent >= -MANT_WIDTH) {
|
||||
const uint32_t idx =
|
||||
exponent < 0
|
||||
? 0
|
||||
: static_cast<uint32_t>(exponent + (IDX_SIZE - 1)) / IDX_SIZE;
|
||||
const uint32_t len = internal::length_for_num(idx * IDX_SIZE, MANT_WIDTH);
|
||||
return len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
LIBC_INLINE constexpr size_t
|
||||
FloatToString<long double>::zero_blocks_after_point() {
|
||||
#ifdef LIBC_COPT_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE
|
||||
return MIN_BLOCK_2[-exponent / IDX_SIZE];
|
||||
#else
|
||||
return 0;
|
||||
// TODO (michaelrj): Find a good algorithm for this that doesn't use a table.
|
||||
#endif
|
||||
}
|
||||
|
||||
template <>
|
||||
@ -377,29 +650,52 @@ 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
|
||||
// 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 + (IDX_SIZE - 1)) / IDX_SIZE;
|
||||
const uint32_t pos_exp = idx * IDX_SIZE;
|
||||
|
||||
// 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);
|
||||
#ifdef LIBC_COPT_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE
|
||||
// ------------------------------ TABLE MODE -------------------------------
|
||||
const int32_t SHIFT_CONST = TABLE_SHIFT_CONST;
|
||||
val = POW10_SPLIT[POW10_OFFSET[idx] + block_index];
|
||||
|
||||
#elif defined(LIBC_COPT_FLOAT_TO_STR_USE_DYADIC_FLOAT) || \
|
||||
defined(LIBC_COPT_FLOAT_TO_STR_USE_DYADIC_FLOAT_LD)
|
||||
// ------------------------ DYADIC FLOAT CALC MODE -------------------------
|
||||
const int32_t SHIFT_CONST = CALC_SHIFT_CONST;
|
||||
val = internal::get_table_positive_df<256>(pos_exp, block_index);
|
||||
#else
|
||||
// ----------------------------- INT CALC MODE -----------------------------
|
||||
const int32_t SHIFT_CONST = CALC_SHIFT_CONST;
|
||||
const uint64_t MAX_POW_2_SIZE =
|
||||
exponent + CALC_SHIFT_CONST - (BLOCK_SIZE * block_index);
|
||||
const uint64_t MAX_POW_5_SIZE =
|
||||
internal::log2_pow5(BLOCK_SIZE * block_index);
|
||||
const uint64_t MAX_INT_SIZE =
|
||||
(MAX_POW_2_SIZE > MAX_POW_5_SIZE) ? MAX_POW_2_SIZE : MAX_POW_5_SIZE;
|
||||
|
||||
if (MAX_INT_SIZE < 1024) {
|
||||
val = internal::get_table_positive<1024>(pos_exp, block_index);
|
||||
} else if (MAX_INT_SIZE < 2048) {
|
||||
val = internal::get_table_positive<2048>(pos_exp, block_index);
|
||||
} else if (MAX_INT_SIZE < 4096) {
|
||||
val = internal::get_table_positive<4096>(pos_exp, block_index);
|
||||
} else if (MAX_INT_SIZE < 8192) {
|
||||
val = internal::get_table_positive<8192>(pos_exp, block_index);
|
||||
} else {
|
||||
val = internal::get_table_positive<16384>(pos_exp, i,
|
||||
POW10_ADDITIONAL_BITS_CALC);
|
||||
val = internal::get_table_positive<16384>(pos_exp, block_index);
|
||||
}
|
||||
#endif
|
||||
const uint32_t shift_amount = SHIFT_CONST + pos_exp - exponent;
|
||||
|
||||
const BlockInt digits =
|
||||
internal::mul_shift_mod_1e9(mantissa, val, (int32_t)(shift_amount));
|
||||
@ -413,31 +709,62 @@ 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;
|
||||
const int32_t idx = -exponent / IDX_SIZE;
|
||||
|
||||
cpp::UInt<MID_INT_SIZE> val;
|
||||
#ifdef LIBC_COPT_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE
|
||||
// ------------------------------ TABLE MODE -------------------------------
|
||||
const int32_t SHIFT_CONST = TABLE_SHIFT_CONST;
|
||||
|
||||
// if the requested block is zero
|
||||
if (i <= MIN_BLOCK_2[idx]) {
|
||||
if (block_index <= 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];
|
||||
const uint32_t p = POW10_OFFSET_2[idx] + block_index - MIN_BLOCK_2[idx];
|
||||
// If every digit after the requested block is zero.
|
||||
if (p >= POW10_OFFSET_2[idx + 1]) {
|
||||
return 0;
|
||||
}
|
||||
val = POW10_SPLIT_2[p];
|
||||
#elif defined(LIBC_COPT_FLOAT_TO_STR_USE_DYADIC_FLOAT) || \
|
||||
defined(LIBC_COPT_FLOAT_TO_STR_USE_DYADIC_FLOAT_LD)
|
||||
// ------------------------ DYADIC FLOAT CALC MODE -------------------------
|
||||
const int32_t SHIFT_CONST = CALC_SHIFT_CONST;
|
||||
|
||||
// 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);
|
||||
val = internal::get_table_negative_df<256>(idx * IDX_SIZE, block_index + 1);
|
||||
#else // table mode
|
||||
// ----------------------------- INT CALC MODE -----------------------------
|
||||
const int32_t SHIFT_CONST = CALC_SHIFT_CONST;
|
||||
|
||||
const uint64_t TEN_BLOCKS = (block_index + 1) * BLOCK_SIZE;
|
||||
const uint64_t MAX_INT_SIZE = internal::log2_pow5(TEN_BLOCKS);
|
||||
|
||||
if (MAX_INT_SIZE < 1024) {
|
||||
val = internal::get_table_negative<1024>(idx * IDX_SIZE, block_index + 1);
|
||||
} else if (MAX_INT_SIZE < 2048) {
|
||||
val = internal::get_table_negative<2048>(idx * IDX_SIZE, block_index + 1);
|
||||
} else if (MAX_INT_SIZE < 4096) {
|
||||
val = internal::get_table_negative<4096>(idx * IDX_SIZE, block_index + 1);
|
||||
} else if (MAX_INT_SIZE < 8192) {
|
||||
val = internal::get_table_negative<8192>(idx * IDX_SIZE, block_index + 1);
|
||||
} else if (MAX_INT_SIZE < 16384) {
|
||||
val =
|
||||
internal::get_table_negative<16384>(idx * IDX_SIZE, block_index + 1);
|
||||
} else {
|
||||
val = internal::get_table_negative<16384 + 8192>(idx * IDX_SIZE,
|
||||
block_index + 1);
|
||||
}
|
||||
#endif
|
||||
const int32_t shift_amount = SHIFT_CONST + (-exponent - IDX_SIZE * idx);
|
||||
BlockInt digits = internal::mul_shift_mod_1e9(mantissa, val, shift_amount);
|
||||
return digits;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LONG_DOUBLE_IS_DOUBLE
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_SUPPORT_FLOAT_TO_STRING_H
|
||||
|
@ -12,6 +12,11 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
constexpr size_t TABLE_SHIFT_CONST = 120;
|
||||
constexpr size_t IDX_SIZE = 16;
|
||||
|
||||
constexpr size_t MID_INT_SIZE = 192;
|
||||
|
||||
static const uint16_t POW10_OFFSET[64] = {
|
||||
0, 2, 5, 8, 12, 16, 21, 26, 32, 39, 46, 54, 62,
|
||||
71, 80, 90, 100, 111, 122, 134, 146, 159, 173, 187, 202, 217,
|
||||
|
59
libc/src/__support/ryu_long_double_constants.h
Normal file
59
libc/src/__support/ryu_long_double_constants.h
Normal file
@ -0,0 +1,59 @@
|
||||
//===-- Ryu Constants for long double conversion ----------------*- 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_RYU_LONG_DOUBLE_CONSTANTS_H
|
||||
#define LLVM_LIBC_SRC_SUPPORT_RYU_LONG_DOUBLE_CONSTANTS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
constexpr size_t TABLE_SHIFT_CONST = 120;
|
||||
constexpr size_t IDX_SIZE = 128;
|
||||
|
||||
constexpr size_t MID_INT_SIZE = (256 + 64);
|
||||
|
||||
static const uint32_t POW10_OFFSET[] = {
|
||||
0, 4, 13, 26, 43, 64, 90, 120, 154, 193, 236,
|
||||
283, 334, 390, 450, 514, 582, 655, 732, 813, 899, 989,
|
||||
1083, 1181, 1284, 1391, 1502, 1618, 1738, 1862, 1990, 2123, 2260,
|
||||
2401, 2547, 2697, 2851, 3009, 3172, 3339, 3510, 3686, 3866, 4050,
|
||||
4238, 4431, 4628, 4829, 5034, 5244, 5458, 5676, 5899, 6126, 6357,
|
||||
6592, 6832, 7076, 7324, 7577, 7834, 8095, 8360, 8630, 8904, 9182,
|
||||
9465, 9752, 10043, 10338, 10638, 10942, 11250, 11563, 11880, 12201, 12526,
|
||||
12856, 13190, 13528, 13871, 14218, 14569, 14924, 15284, 15648, 16016, 16388,
|
||||
16765, 17146, 17531, 17921, 18315, 18713, 19115, 19522, 19933, 20348, 20768,
|
||||
21192, 21620, 22052, 22489, 22930, 23375, 23825, 24279, 24737, 25199, 25666,
|
||||
26137, 26612, 27092, 27576, 28064, 28556, 29053, 29554, 30059, 30568, 31082,
|
||||
31600, 32122, 32649, 33180, 33715, 34254, 34798, 35346};
|
||||
|
||||
static const uint32_t POW10_OFFSET_2[130] = {
|
||||
0, 15, 44, 83, 131, 190, 259, 338, 426, 524, 633,
|
||||
751, 879, 1017, 1166, 1324, 1492, 1670, 1858, 2056, 2264, 2482,
|
||||
2709, 2947, 3195, 3453, 3720, 3997, 4285, 4582, 4889, 5206, 5534,
|
||||
5871, 6218, 6575, 6941, 7318, 7705, 8102, 8508, 8925, 9352, 9788,
|
||||
10234, 10690, 11157, 11633, 12119, 12615, 13122, 13638, 14164, 14700, 15245,
|
||||
15801, 16367, 16943, 17528, 18124, 18730, 19345, 19970, 20605, 21251, 21906,
|
||||
22571, 23246, 23931, 24626, 25331, 26046, 26770, 27505, 28250, 29004, 29768,
|
||||
30543, 31328, 32122, 32926, 33740, 34565, 35399, 36243, 37097, 37961, 38835,
|
||||
39719, 40613, 41516, 42430, 43354, 44287, 45230, 46184, 47148, 48121, 49104,
|
||||
50097, 51100, 52113, 53136, 54169, 55212, 56265, 57328, 58400, 59482, 60575,
|
||||
61678, 62790, 63912, 65045, 66188, 67340, 68502, 69674, 70856, 72048, 73250,
|
||||
74462, 75684, 76916, 78158, 79409, 80670, 81942, 83224, 84515};
|
||||
|
||||
static const uint16_t MIN_BLOCK_2[130] = {
|
||||
0, 0, 4, 9, 13, 17, 21, 26, 30, 34, 39, 43, 47, 51, 56,
|
||||
60, 64, 68, 73, 77, 81, 86, 90, 94, 98, 103, 107, 111, 116, 120,
|
||||
124, 128, 133, 137, 141, 146, 150, 154, 158, 163, 167, 171, 176, 180, 184,
|
||||
188, 193, 197, 201, 205, 210, 214, 218, 223, 227, 231, 235, 240, 244, 248,
|
||||
253, 257, 261, 265, 270, 274, 278, 283, 287, 291, 295, 300, 304, 308, 313,
|
||||
317, 321, 325, 330, 334, 338, 342, 347, 351, 355, 360, 364, 368, 372, 377,
|
||||
381, 385, 390, 394, 398, 402, 407, 411, 415, 420, 424, 428, 432, 437, 441,
|
||||
445, 450, 454, 458, 462, 467, 471, 475, 479, 484, 488, 492, 497, 501, 505,
|
||||
509, 514, 518, 522, 527, 531, 535, 539, 544, 0};
|
||||
|
||||
#endif // LLVM_LIBC_SRC_SUPPORT_RYU_LONG_DOUBLE_CONSTANTS_H
|
@ -99,6 +99,8 @@ add_object_library(
|
||||
libc.src.__support.uint128
|
||||
libc.src.__support.integer_to_string
|
||||
libc.src.__support.float_to_string
|
||||
# COMPILE_OPTIONS
|
||||
# -DLIBC_COPT_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE
|
||||
)
|
||||
|
||||
|
||||
|
@ -28,8 +28,8 @@ int convert(Writer *writer, const FormatSection &to_conv) {
|
||||
if (!to_conv.has_conv)
|
||||
return writer->write(to_conv.raw_string);
|
||||
|
||||
#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT
|
||||
// TODO(michaelrj): Undo this once decimal long double support is done.
|
||||
#if !defined(LIBC_COPT_PRINTF_DISABLE_FLOAT) && \
|
||||
defined(LIBC_COPT_PRINTF_HEX_LONG_DOUBLE)
|
||||
if (to_conv.length_modifier == LengthModifier::L) {
|
||||
switch (to_conv.conv_name) {
|
||||
case 'f':
|
||||
|
@ -29,6 +29,14 @@
|
||||
#define LIBC_COPT_PRINTF_INDEX_ARR_LEN 128
|
||||
#endif
|
||||
|
||||
// TODO(michaelrj): Provide a proper interface for these options.
|
||||
// LIBC_COPT_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE
|
||||
// LIBC_COPT_FLOAT_TO_STR_USE_DYADIC_FLOAT
|
||||
// LIBC_COPT_FLOAT_TO_STR_USE_DYADIC_FLOAT_LD
|
||||
// LIBC_COPT_FLOAT_TO_STR_USE_INT_CALC
|
||||
// LIBC_COPT_FLOAT_TO_STR_NO_TABLE
|
||||
// LIBC_COPT_PRINTF_HEX_LONG_DOUBLE
|
||||
|
||||
// TODO(michaelrj): Move the other printf configuration options into this file.
|
||||
|
||||
#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PRINTF_CONFIG_H
|
||||
|
@ -930,16 +930,19 @@ TEST_F(LlvmLibcSPrintfTest, FloatDecimalConv) {
|
||||
|
||||
// TODO: Fix long doubles (needs bigger table or alternate algorithm.)
|
||||
// Currently the table values are generated, which is very slow.
|
||||
/*
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "%Lf", 1.0L);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.000000");
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "%Lf", 1e100L);
|
||||
ASSERT_STREQ_LEN(written, buff,
|
||||
"99999999999999999996693535322073426194986990198284960792713"
|
||||
"91541752018669482644324418977840117055488.000000");
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "%Lf", 1.0L);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.000000");
|
||||
|
||||
char big_buff[10000];
|
||||
|
||||
// written = __llvm_libc::sprintf(big_buff, "%Lf", 0x1p16383L);
|
||||
|
||||
written = __llvm_libc::sprintf(big_buff, "%Lf", 1e1000L);
|
||||
ASSERT_STREQ_LEN(
|
||||
written, big_buff,
|
||||
@ -1031,7 +1034,122 @@ TEST_F(LlvmLibcSPrintfTest, FloatDecimalConv) {
|
||||
"739074789794941408428328217107759915202650066155868439585510978709442590"
|
||||
"231934194956788626761834746430104077432547436359522462253411168467463134"
|
||||
"24896.000000");
|
||||
*/
|
||||
|
||||
|
||||
written = __llvm_libc::sprintf(big_buff, "%.10Lf", 1e-10L);
|
||||
ASSERT_STREQ_LEN(
|
||||
written, big_buff, "0.0000000001");
|
||||
|
||||
written = __llvm_libc::sprintf(big_buff, "%.7500Lf", 1e-4900L);
|
||||
ASSERT_STREQ_LEN(
|
||||
written, big_buff,
|
||||
"0."
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"000099999999999999999996962764452956071352139203248614920751610856665084"
|
||||
"549214352477698417183862158583009348897567779527408501588132175167211539"
|
||||
"462139941448204886585901454195352527238724272760638086779284030512649793"
|
||||
"039219351187928723378036480041948464946018272171365770411701020666925613"
|
||||
"422460317465324758217878522666789603627480490870456508256359180089236338"
|
||||
"765625231186929290294207420828927406735690318849109129700396907705735097"
|
||||
"663944722727287361650042373203763784830198232253311807069225650324196304"
|
||||
"532045014970637489181357566354288111205943347410488298480279857453705249"
|
||||
"232862728556860184412369114663536200895729846877559808001004454634804626"
|
||||
"541455540260282018142615835686583304903486353937549394736905011798466731"
|
||||
"536563240053860118551127061960208467764243724656897127545613968909523389"
|
||||
"577188368809623987105800147797280462974804046545425080530020901531407223"
|
||||
"191237123282274818236437397994019915368657474589800678444589412286037789"
|
||||
"891525464936023205313685584525510094270344601331453730179416773626565262"
|
||||
"480345858564672442896904520146956686863172737711483866766404977719744767"
|
||||
"834324844875237277613991088218774564658513875732403456058414595576806383"
|
||||
"115554713240005982141397577420073082470139244845624915873825746771661332"
|
||||
"098677966580506186966978746832443976821987300902957597498388211921362869"
|
||||
"017846215557612829071692275292036211064515305528052919611691470945774714"
|
||||
"135516559501572279732350629089770249554808690411603894492333360300589658"
|
||||
"470898965370892774715815089075170720164713889237058574941489766701880158"
|
||||
"060081295483989540170337129032188818293132770882381428397119039835946745"
|
||||
"549356649433406617266370644136291924838857814675939156677910783740103207"
|
||||
"523299367093130816446415259371931925208362367989095199399211644084543790"
|
||||
"110432339056231037520216864358899218874658268610955002763260912337688947"
|
||||
"822453100821038299301092582962825965939081817836419126254832772002214908"
|
||||
"085575905761843610944187009818156363893015929300295112598059949496854566"
|
||||
"638748010633726861510500653821408135845840123073754133549077708843800674"
|
||||
"328440913743105608636458354618912183716456158809545183074062249922212944"
|
||||
"249667793845728355381309084891765979111348980470647082269921872595470473"
|
||||
"719354467594516320911964549508538492057120740224559944452120552719041944"
|
||||
"961475548547884309626382512432626380881023756568143060204097921571153170"
|
||||
"723817845809196253498326358439807445210362177680590181657555380795450462"
|
||||
"223805222580359379367452693270553602179122419370586308101820559214330382"
|
||||
"570449525088342437216896462077260223998756027453411520977536701491759878"
|
||||
"422771447006016890777855573925295187921971811871399320142563330377888532"
|
||||
"179817332113");
|
||||
|
||||
/*
|
||||
written = __llvm_libc::sprintf(buff, "%La", 0.1L);
|
||||
#if defined(SPECIAL_X86_LONG_DOUBLE)
|
||||
|
204
libc/utils/mathtools/ryu_tablegen.py
Normal file
204
libc/utils/mathtools/ryu_tablegen.py
Normal file
@ -0,0 +1,204 @@
|
||||
"""
|
||||
//===-- Table Generator for Ryu Printf ------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
This file is used to generate the tables of values in
|
||||
src/__support/ryu_constants.h and ryu_long_double constants.h. To use it, set
|
||||
the constants at the top of the file to the values you want to use for the Ryu
|
||||
algorithm, then run this file. It will output the appropriate tables to stdout,
|
||||
so it's recommended to pipe stdout to a file. The following is a brief
|
||||
explenation of each of the constants.
|
||||
|
||||
BLOCK_SIZE:
|
||||
Default: 9
|
||||
The number of digits that will be calculated together in a block.
|
||||
Don't touch this unless you really know what you're doing.
|
||||
|
||||
CONSTANT:
|
||||
Default: 120
|
||||
Also known as c_0 and c_1 in the Ryu Printf paper and SHIFT_CONST in
|
||||
float_to_string.h.
|
||||
The table value is shifted left by this amount, and the final value is
|
||||
shifted right by this amount. It effectively makes the table value a fixed
|
||||
point number with the decimal point at the bit that is CONSTANT bits from
|
||||
the right.
|
||||
Higher values increase accuracy, but also require higher MID_INT_WIDTH
|
||||
values to fit the result.
|
||||
|
||||
IDX_SIZE:
|
||||
Default: 16
|
||||
By increasing the MOD_SIZE slightly we can significantly decrease the number
|
||||
of table entries we need.
|
||||
We can divide the number of table entries by IDX_SIZE, and multiply MOD_SIZE
|
||||
by 2^IDX_SIZE, and the math still works out.
|
||||
This optimization isn't mentioned in the original Ryu Printf paper but it
|
||||
saves a lot of space.
|
||||
|
||||
MID_INT_WIDTH:
|
||||
Default: 192
|
||||
This is the size of integer that the tables use. It's called mid int because
|
||||
it's the integer used in the middle of the calculation. There are large ints
|
||||
used to calculate the mid int table values, then those are used to calculate
|
||||
the small int final values.
|
||||
This must be divisible by 64 since each table entry is an array of 64 bit
|
||||
integers.
|
||||
If this is too small, then the results will get cut off. It should be at
|
||||
least CONSTANT + IDX_SIZE + log_2(10^9) to be able to fit the table values.
|
||||
|
||||
MANT_WIDTH:
|
||||
The width of the widest float mantissa that this table will work for.
|
||||
This has a small effect on table size.
|
||||
|
||||
EXP_WIDTH:
|
||||
The width of the widest float exponent that this table will work for.
|
||||
This has a large effect on table size.
|
||||
Specifically, table size is proportional to the square of this number.
|
||||
"""
|
||||
|
||||
BLOCK_SIZE = 9
|
||||
|
||||
|
||||
# Values for double
|
||||
# CONSTANT = 120
|
||||
# IDX_SIZE = 16
|
||||
# MANT_WIDTH = 52
|
||||
# EXP_WIDTH = 11
|
||||
# MID_INT_SIZE = 192
|
||||
|
||||
# Values for 128 bit float
|
||||
CONSTANT = 120
|
||||
IDX_SIZE = 128
|
||||
MANT_WIDTH = 112
|
||||
EXP_WIDTH = 15
|
||||
MID_INT_SIZE = 256 + 64
|
||||
|
||||
MAX_EXP = 2 ** (EXP_WIDTH - 1)
|
||||
POSITIVE_ARR_SIZE = MAX_EXP // IDX_SIZE
|
||||
NEGATIVE_ARR_SIZE = (MAX_EXP // IDX_SIZE) + ((MANT_WIDTH + (IDX_SIZE - 1)) // IDX_SIZE)
|
||||
MOD_SIZE = (10**BLOCK_SIZE) << (CONSTANT + (IDX_SIZE if IDX_SIZE > 1 else 0))
|
||||
|
||||
|
||||
# floor(5^(-9i) * 2^(e + c_1 - 9i) + 1) % (10^9 * 2^c_1)
|
||||
def get_table_positive(exponent, i):
|
||||
pow_of_two = 1 << (exponent + CONSTANT - (BLOCK_SIZE * i))
|
||||
pow_of_five = 5 ** (BLOCK_SIZE * i)
|
||||
result = (pow_of_two // pow_of_five) + 1
|
||||
return result % MOD_SIZE
|
||||
|
||||
|
||||
# floor(10^(9*(-i)) * 2^(c_0 + (-e))) % (10^9 * 2^c_0)
|
||||
def get_table_negative(exponent, i):
|
||||
result = 1
|
||||
pow_of_ten = 10 ** (BLOCK_SIZE * i)
|
||||
shift_amount = CONSTANT - exponent
|
||||
if shift_amount < 0:
|
||||
result = pow_of_ten >> (-shift_amount)
|
||||
else:
|
||||
result = pow_of_ten << (shift_amount)
|
||||
return result % MOD_SIZE
|
||||
|
||||
|
||||
# Returns floor(log_10(2^e)); requires 0 <= e <= 42039.
|
||||
def ceil_log10_pow2(e):
|
||||
return ((e * 0x13441350FBD) >> 42) + 1
|
||||
|
||||
|
||||
def length_for_num(idx, index_size=IDX_SIZE):
|
||||
return (
|
||||
ceil_log10_pow2(idx * index_size) + ceil_log10_pow2(MANT_WIDTH) + BLOCK_SIZE - 1
|
||||
) // BLOCK_SIZE
|
||||
|
||||
|
||||
def get_64bit_window(num, index):
|
||||
return (num >> (index * 64)) % (2**64)
|
||||
|
||||
|
||||
def mid_int_to_str(num):
|
||||
outstr = " {"
|
||||
outstr += str(get_64bit_window(num, 0)) + "u"
|
||||
for i in range(1, MID_INT_SIZE // 64):
|
||||
outstr += ", " + str(get_64bit_window(num, i)) + "u"
|
||||
outstr += "},"
|
||||
return outstr
|
||||
|
||||
|
||||
def print_positive_table_for_idx(idx):
|
||||
positive_blocks = length_for_num(idx)
|
||||
for i in range(positive_blocks):
|
||||
table_val = get_table_positive(idx * IDX_SIZE, i)
|
||||
# print(hex(table_val))
|
||||
print(mid_int_to_str(table_val))
|
||||
return positive_blocks
|
||||
|
||||
|
||||
def print_negative_table_for_idx(idx):
|
||||
i = 0
|
||||
min_block = -1
|
||||
table_val = 0
|
||||
MIN_USEFUL_VAL = 2 ** (CONSTANT - (MANT_WIDTH + 2))
|
||||
# Iterate through the zero blocks
|
||||
while table_val < MIN_USEFUL_VAL:
|
||||
i += 1
|
||||
table_val = get_table_negative((idx) * IDX_SIZE, i)
|
||||
else:
|
||||
i -= 1
|
||||
|
||||
min_block = i
|
||||
|
||||
# Iterate until another zero block is found
|
||||
while table_val >= MIN_USEFUL_VAL:
|
||||
table_val = get_table_negative((idx) * IDX_SIZE, i + 1)
|
||||
if table_val >= MIN_USEFUL_VAL:
|
||||
print(mid_int_to_str(table_val))
|
||||
i += 1
|
||||
return i - min_block, min_block
|
||||
|
||||
|
||||
positive_size_arr = [0] * (POSITIVE_ARR_SIZE + 1)
|
||||
|
||||
negative_size_arr = [0] * (NEGATIVE_ARR_SIZE + 1)
|
||||
min_block_arr = [0] * (NEGATIVE_ARR_SIZE + 1)
|
||||
acc = 0
|
||||
|
||||
if MOD_SIZE > (2**MID_INT_SIZE):
|
||||
print(
|
||||
"Mod size is too big for current MID_INT_SIZE by a factor of",
|
||||
MOD_SIZE // (2**MID_INT_SIZE),
|
||||
)
|
||||
else:
|
||||
print("static const uint64_t POW10_SPLIT[][" + str(MID_INT_SIZE // 64) + "] = {")
|
||||
for idx in range(0, POSITIVE_ARR_SIZE):
|
||||
num_size = print_positive_table_for_idx(idx)
|
||||
acc += num_size
|
||||
positive_size_arr[idx + 1] = acc
|
||||
print("};")
|
||||
|
||||
print(
|
||||
"static const uint32_t POW10_OFFSET_2[" + str(len(positive_size_arr)) + "] = {",
|
||||
str(positive_size_arr)[1:-2],
|
||||
"};",
|
||||
)
|
||||
|
||||
print("static const uint64_t POW10_SPLIT_2[][" + str(MID_INT_SIZE // 64) + "] = {")
|
||||
for idx in range(0, NEGATIVE_ARR_SIZE):
|
||||
num_size, min_block = print_negative_table_for_idx(idx)
|
||||
acc += num_size
|
||||
negative_size_arr[idx + 1] = acc
|
||||
min_block_arr[idx] = min_block
|
||||
print("};")
|
||||
print(
|
||||
"static const uint32_t POW10_OFFSET_2[" + str(len(negative_size_arr)) + "] = {",
|
||||
str(negative_size_arr)[1:-2],
|
||||
"};",
|
||||
)
|
||||
print(
|
||||
"static const uint16_t MIN_BLOCK_2[" + str(len(min_block_arr)) + "] = {",
|
||||
str(min_block_arr)[1:-2],
|
||||
"};",
|
||||
)
|
@ -310,10 +310,14 @@ libc_support_library(
|
||||
hdrs = [
|
||||
"src/__support/float_to_string.h",
|
||||
"src/__support/ryu_constants.h",
|
||||
"src/__support/ryu_long_double_constants.h",
|
||||
],
|
||||
# This is temporarily commented out since the table is too large to land in the same patch as the rest of the changes.
|
||||
# defines = ["LIBC_COPT_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE"],
|
||||
deps = [
|
||||
":__support_common",
|
||||
":__support_cpp_type_traits",
|
||||
":__support_fputil_dyadic_float",
|
||||
":__support_fputil_fp_bits",
|
||||
":__support_libc_assert",
|
||||
":__support_uint",
|
||||
@ -759,6 +763,7 @@ libc_support_library(
|
||||
":__support_common",
|
||||
":__support_fputil_multiply_add",
|
||||
":__support_number_pair",
|
||||
":libc_root",
|
||||
],
|
||||
)
|
||||
|
||||
@ -772,6 +777,7 @@ libc_support_library(
|
||||
":__support_fputil_multiply_add",
|
||||
":__support_macros_optimization",
|
||||
":__support_uint",
|
||||
":libc_root",
|
||||
],
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user