#ifndef _LIBCPP_SRC_INCLUDE_TO_CHARS_FLOATING_POINT_H
#define _LIBCPP_SRC_INCLUDE_TO_CHARS_FLOATING_POINT_H
#include <__algorithm/find.h>
#include <__algorithm/find_if.h>
#include <__algorithm/lower_bound.h>
#include <__algorithm/min.h>
#include <__assert>
#include <__config>
#include <__functional/operations.h>
#include <__iterator/access.h>
#include <__iterator/size.h>
#include <bit>
#include <cfloat>
#include <climits>
#include "include/ryu/ryu.h"
_LIBCPP_BEGIN_NAMESPACE_STD
namespace __itoa {
inline constexpr char _Charconv_digits[] = …;
static_assert …;
}
template <class _FloatingType>
struct _Floating_type_traits;
template <>
struct _Floating_type_traits<float> { … };
template <>
struct _Floating_type_traits<double> { … };
template <class _Floating>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
to_chars_result _Floating_to_chars_hex_precision(
char* _First, char* const _Last, const _Floating _Value, int _Precision) noexcept { … }
template <class _Floating>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
to_chars_result _Floating_to_chars_hex_shortest(
char* _First, char* const _Last, const _Floating _Value) noexcept { … }
#if 0
#include <algorithm>
#include <assert.h>
#include <charconv>
#include <cmath>
#include <limits>
#include <map>
#include <stdint.h>
#include <stdio.h>
#include <system_error>
#include <type_traits>
#include <vector>
using namespace std;
template <typename UInt, typename Pred>
[[nodiscard]] UInt uint_partition_point(UInt first, const UInt last, Pred pred) {
static_assert(is_unsigned_v<UInt>);
assert(first <= last);
for (UInt n = last - first; n > 0;) {
const UInt n2 = n / 2;
const UInt mid = first + n2;
if (pred(mid)) {
first = mid + 1;
n = n - n2 - 1;
} else {
n = n2;
}
}
return first;
}
template <typename Floating>
[[nodiscard]] int scientific_exponent_X(const int P, const Floating flt) {
char buf[400];
const auto to_result = to_chars(buf, end(buf), flt, chars_format::scientific, P - 1);
assert(to_result.ec == errc{});
const char* exp_ptr = find(buf, to_result.ptr, 'e');
assert(exp_ptr != to_result.ptr);
++exp_ptr;
if (*exp_ptr == '+') {
++exp_ptr;
}
int X;
const auto from_result = from_chars(exp_ptr, to_result.ptr, X);
assert(from_result.ec == errc{});
return X;
}
template <typename UInt>
void print_table(const vector<UInt>& v, const char* const name) {
constexpr const char* UIntName = _IsSame<UInt, uint32_t>::value ? "uint32_t" : "uint64_t";
printf("static constexpr %s %s[%zu] = {\n", UIntName, name, v.size());
for (const auto& val : v) {
if constexpr (_IsSame<UInt, uint32_t>::value) {
printf("0x%08Xu,\n", val);
} else {
printf("0x%016llXu,\n", val);
}
}
printf("};\n");
}
enum class Mode { Tables, Tests };
template <typename Floating>
void generate_tables(const Mode mode) {
using Limits = numeric_limits<Floating>;
using UInt = conditional_t<_IsSame<Floating, float>::value, uint32_t, uint64_t>;
map<int, map<int, UInt>> P_X_LargestValWithX;
constexpr int MaxP = Limits::max_exponent10 + 1;
for (int P = 1; P <= MaxP; ++P) {
for (int X = -5; X < P; ++X) {
constexpr Floating first = static_cast<Floating>(9e-5);
constexpr Floating last = Limits::infinity();
const UInt val_beyond_X = uint_partition_point(reinterpret_cast<const UInt&>(first),
reinterpret_cast<const UInt&>(last),
[P, X](const UInt u) { return scientific_exponent_X(P, reinterpret_cast<const Floating&>(u)) <= X; });
P_X_LargestValWithX[P][X] = val_beyond_X - 1;
}
}
constexpr const char* FloatingName = _IsSame<Floating, float>::value ? "float" : "double";
constexpr int MaxSpecialP = _IsSame<Floating, float>::value ? 7 : 15;
if (mode == Mode::Tables) {
printf("template <>\n");
printf("struct _General_precision_tables<%s> {\n", FloatingName);
printf("static constexpr int _Max_special_P = %d;\n", MaxSpecialP);
vector<UInt> special;
for (int P = 1; P <= MaxSpecialP; ++P) {
for (int X = -5; X < P; ++X) {
const UInt val = P_X_LargestValWithX[P][X];
special.push_back(val);
}
}
print_table(special, "_Special_X_table");
for (int P = MaxSpecialP + 1; P < MaxP; ++P) {
for (int X = -5; X < P; ++X) {
const UInt val = P_X_LargestValWithX[P][X];
assert(val == P_X_LargestValWithX[MaxP][X]);
}
}
printf("static constexpr int _Max_P = %d;\n", MaxP);
vector<UInt> ordinary;
for (int X = -5; X < MaxP; ++X) {
const UInt val = P_X_LargestValWithX[MaxP][X];
ordinary.push_back(val);
}
print_table(ordinary, "_Ordinary_X_table");
printf("};\n");
} else {
printf("==========\n");
printf("Test cases for %s:\n", FloatingName);
constexpr int Hexits = _IsSame<Floating, float>::value ? 6 : 13;
constexpr const char* Suffix = _IsSame<Floating, float>::value ? "f" : "";
for (int P = 1; P <= MaxP; ++P) {
for (int X = -5; X < P; ++X) {
if (P <= MaxSpecialP || P == 25 || P == MaxP || X == P - 1) {
const UInt val1 = P_X_LargestValWithX[P][X];
const Floating f1 = reinterpret_cast<const Floating&>(val1);
const UInt val2 = val1 + 1;
const Floating f2 = reinterpret_cast<const Floating&>(val2);
printf("{%.*a%s, chars_format::general, %d, \"%.*g\"},\n", Hexits, f1, Suffix, P, P, f1);
if (isfinite(f2)) {
printf("{%.*a%s, chars_format::general, %d, \"%.*g\"},\n", Hexits, f2, Suffix, P, P, f2);
}
}
}
}
}
}
int main() {
printf("template <class _Floating>\n");
printf("struct _General_precision_tables;\n");
generate_tables<float>(Mode::Tables);
generate_tables<double>(Mode::Tables);
generate_tables<float>(Mode::Tests);
generate_tables<double>(Mode::Tests);
}
#endif
template <class _Floating>
struct _General_precision_tables;
template <>
struct _General_precision_tables<float> { … };
template <>
struct _General_precision_tables<double> { … };
template <class _Floating>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
to_chars_result _Floating_to_chars_general_precision(
char* _First, char* const _Last, const _Floating _Value, int _Precision) noexcept { … }
enum class _Floating_to_chars_overload { … };
template <_Floating_to_chars_overload _Overload, class _Floating>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
to_chars_result _Floating_to_chars(
char* _First, char* const _Last, _Floating _Value, const chars_format _Fmt, const int _Precision) noexcept { … }
_LIBCPP_END_NAMESPACE_STD
#endif