This commit is contained in:
Syoyo Fujita
2025-04-03 05:00:36 +09:00
parent 2be4212806
commit fbd597c205
3 changed files with 522 additions and 183 deletions

View File

@@ -1,23 +1,21 @@
#include <vector>
#include <iostream>
#include <sstream>
#include <chrono>
#include <cstring>
#include <iostream>
#include <random>
#include <sstream>
#include <vector>
#include "dragonbox_to_chars.h"
#include "dtoa_milo.h"
std::vector<float> gen_floats(size_t n) {
std::vector<float> dst;
dst.resize(n);
std::random_device rd;
std::mt19937 engine(rd());
std::uniform_real_distribution<> dist(-0.001, 0.01);
std::uniform_real_distribution<> dist(-0.1, 0.1);
for (size_t i = 0; i < n; i++) {
double f = dist(engine);
@@ -27,14 +25,13 @@ std::vector<float> gen_floats(size_t n) {
return dst;
}
//
// based on fmtlib
//
//
// TOOD: Use builtin_clz insturction
// TOOD: Use builtin_clz insturction
// T = uint32 or uint64
template<typename T>
template <typename T>
inline int count_digits(T n) {
int count = 1;
for (;;) {
@@ -50,107 +47,118 @@ inline int count_digits(T n) {
}
}
// Converts value in the range [0, 100) to a string.
// GCC generates slightly better code when value is pointer-size.
inline auto digits2(size_t value) -> const char* {
// Align data since unaligned access may be slower when crossing a
// hardware-specific boundary.
alignas(2) static const char data[] =
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
return &data[value * 2];
// Converts value in the range [0, 100) to a string.
// GCC generates slightly better code when value is pointer-size.
inline auto digits2(size_t value) -> const char* {
// Align data since unaligned access may be slower when crossing a
// hardware-specific boundary.
alignas(2) static const char data[] =
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
return &data[value * 2];
}
// Writes a two-digit value to out.
inline void write2digits(char* out, size_t value) {
// if (!is_constant_evaluated() && std::is_same<Char, char>::value &&
// !FMT_OPTIMIZE_SIZE) {
// memcpy(out, digits2(value), 2);
// return;
// }
*out++ = static_cast<char>('0' + value / 10);
*out = static_cast<char>('0' + value % 10);
}
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
char* write_exponent(int exp, char* out) {
// FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range");
if (exp < 0) {
*out++ = '-';
exp = -exp;
} else {
*out++ = '+';
}
// Writes a two-digit value to out.
inline void write2digits(char* out, size_t value) {
//if (!is_constant_evaluated() && std::is_same<Char, char>::value &&
// !FMT_OPTIMIZE_SIZE) {
// memcpy(out, digits2(value), 2);
// return;
//}
*out++ = static_cast<char>('0' + value / 10);
*out = static_cast<char>('0' + value % 10);
auto uexp = static_cast<uint32_t>(exp);
// if (is_constant_evaluated()) {
// if (uexp < 10) *out++ = '0';
// return format_decimal<Char>(out, uexp, count_digits(uexp));
// }
if (uexp >= 100u) {
const char* top = digits2(uexp / 100);
if (uexp >= 1000u) *out++ = top[0];
*out++ = static_cast<char>(top[1]);
uexp %= 100;
}
const char* d = digits2(uexp);
*out++ = static_cast<char>(d[0]);
*out++ = static_cast<char>(d[1]);
return out;
}
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
char *write_exponent(int exp, char *out) {
//FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range");
if (exp < 0) {
*out++ = '-';
exp = -exp;
} else {
*out++ = '+';
}
auto uexp = static_cast<uint32_t>(exp);
//if (is_constant_evaluated()) {
// if (uexp < 10) *out++ = '0';
// return format_decimal<Char>(out, uexp, count_digits(uexp));
//}
if (uexp >= 100u) {
const char* top = digits2(uexp / 100);
if (uexp >= 1000u) *out++ = top[0];
*out++ = static_cast<char>(top[1]);
uexp %= 100;
}
const char* d = digits2(uexp);
*out++ = static_cast<char>(d[0]);
*out++ = static_cast<char>(d[1]);
return out;
}
inline char *fill_n(char *p, int n, char c) {
inline char* fill_n(char* p, int n, char c) {
for (int i = 0; i < n; i++, p++) {
*p = c;
*p = c;
}
return p;
}
inline char *format_decimal(char* out, uint64_t value, uint32_t size) {
//FMT_ASSERT(size >= count_digits(value), "invalid digit count");
unsigned n = size;
while (value >= 100) {
// Integer division is slow so do it for a group of two digits instead
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
n -= 2;
write2digits(out + n, static_cast<unsigned>(value % 100));
value /= 100;
}
if (value >= 10) {
n -= 2;
write2digits(out + n, static_cast<unsigned>(value));
} else {
out[--n] = static_cast<char>('0' + value);
}
return out + n;
inline void format_decimal_impl(char* out, uint64_t value, uint32_t size) {
// FMT_ASSERT(size >= count_digits(value), "invalid digit count");
unsigned n = size;
while (value >= 100) {
// Integer division is slow so do it for a group of two digits instead
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
n -= 2;
write2digits(out + n, static_cast<unsigned>(value % 100));
value /= 100;
}
inline char* write_significand(char* out, uint64_t significand, int significand_size,
int integral_size, char decimal_point) {
if (!decimal_point) return format_decimal(out, significand, significand_size);
out += significand_size + 1;
char* end = out;
int floating_size = significand_size - integral_size;
for (int i = floating_size / 2; i > 0; --i) {
out -= 2;
write2digits(out, static_cast<std::size_t>(significand % 100));
significand /= 100;
}
if (floating_size % 2 != 0) {
*--out = static_cast<char>('0' + significand % 10);
significand /= 10;
}
*--out = decimal_point;
format_decimal(out - integral_size, significand, integral_size);
return end;
if (value >= 10) {
n -= 2;
write2digits(out + n, static_cast<unsigned>(value));
} else {
out[--n] = static_cast<char>('0' + value);
}
//return out + n;
}
char *write_float(const float f, char *buf)
{
inline char* format_decimal(char* out, uint64_t value, uint32_t num_digits) {
format_decimal_impl(out, value, num_digits);
return out + num_digits;
}
inline char* write_significand_e(char* out, uint64_t significand,
int significand_size, int exponent) {
out = format_decimal(out, significand, significand_size);
return fill_n(out, exponent, '0');
}
inline char* write_significand(char* out, uint64_t significand,
int significand_size, int integral_size,
char decimal_point) {
if (!decimal_point) return format_decimal(out, significand, significand_size);
out += significand_size + 1;
char* end = out;
int floating_size = significand_size - integral_size;
for (int i = floating_size / 2; i > 0; --i) {
out -= 2;
write2digits(out, static_cast<std::size_t>(significand % 100));
significand /= 100;
}
if (floating_size % 2 != 0) {
*--out = static_cast<char>('0' + significand % 10);
significand /= 10;
}
*--out = decimal_point;
format_decimal(out - integral_size, significand, integral_size);
return end;
}
char* write_float(const double f, char* buf) {
const int spec_precision = -1; // unlimited
bool is_negative = std::signbit(f);
@@ -158,7 +166,7 @@ char *write_float(const float f, char *buf)
// print human-readable float for the value in range [1e-4, 1e+16]
const int exp_lower = -4;
const int exp_upper = 16; // (15 + 1) for double, (6+1) for float
const int exp_upper = 16; // (15 + 1) for double, (6+1) for float
char exp_char = 'e';
char zero_char = '0';
@@ -168,92 +176,118 @@ char *write_float(const float f, char *buf)
size_t size = size_t(significand_size) + (is_negative ? 1u : 0u);
int output_exp = ret.exponent + significand_size - 1;
bool use_exp_format = (output_exp < exp_lower) || (output_exp >= exp_upper);
bool use_exp_format = (output_exp < exp_lower) || (output_exp >= exp_upper);
char decimal_point = '.';
if (use_exp_format) {
int num_zeros = 0;
if (significand_size == 1) {
decimal_point = '\0';
}
auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp;
int exp_digits = 2;
if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3;
auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp;
int exp_digits = 2;
if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3;
size += (decimal_point ? 1u : 0u) + 2u + size_t(exp_digits);
if (is_negative) {
*buf++ = '-';
*buf++ = '-';
}
buf = write_significand(buf, significand, significand_size, 1, decimal_point);
buf =
write_significand(buf, significand, significand_size, 1, decimal_point);
if (num_zeros > 0) buf = fill_n(buf, num_zeros, zero_char);
*buf++ = exp_char;
return write_exponent(output_exp, buf);
if (num_zeros > 0) buf = fill_n(buf, num_zeros, zero_char);
*buf++ = exp_char;
return write_exponent(output_exp, buf);
}
int exp = f.exponent + significand_size;
if (f.exponent >= 0) {
// 1234e5 -> 123400000[.0+]
size += to_unsigned(f.exponent);
int num_zeros = specs.precision - exp;
abort_fuzzing_if(num_zeros > 5000);
if (specs.alt()) {
++size;
if (num_zeros <= 0 && specs.type() != presentation_type::fixed)
num_zeros = 0;
if (num_zeros > 0) size += to_unsigned(num_zeros);
}
auto grouping = Grouping(loc, specs.localized());
size += to_unsigned(grouping.count_separators(exp));
return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
if (s != sign::none) *it++ = detail::getsign<Char>(s);
it = write_significand<Char>(it, significand, significand_size,
f.exponent, grouping);
if (!specs.alt()) return it;
*it++ = decimal_point;
return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
});
} else if (exp > 0) {
// 1234e-2 -> 12.34[0+]
int num_zeros = specs.alt() ? specs.precision - significand_size : 0;
size += 1 + static_cast<unsigned>(max_of(num_zeros, 0));
auto grouping = Grouping(loc, specs.localized());
size += to_unsigned(grouping.count_separators(exp));
return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
if (s != sign::none) *it++ = detail::getsign<Char>(s);
it = write_significand(it, significand, significand_size, exp,
decimal_point, grouping);
return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
});
}
// 1234e-6 -> 0.001234
int num_zeros = -exp;
if (significand_size == 0 && specs.precision >= 0 &&
specs.precision < num_zeros) {
num_zeros = specs.precision;
}
bool pointy = num_zeros != 0 || significand_size != 0 || specs.alt();
size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros);
return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
if (s != sign::none) *it++ = detail::getsign<Char>(s);
*it++ = zero;
if (!pointy) return it;
*it++ = decimal_point;
it = detail::fill_n(it, num_zeros, zero);
return write_significand<Char>(it, significand, significand_size);
});
int exp = ret.exponent + significand_size;
if (ret.exponent >= 0) {
// 1234e5 -> 123400000[.0+]
size += static_cast<size_t>(ret.exponent);
int num_zeros = spec_precision - exp;
// abort_fuzzing_if(num_zeros > 5000);
// if (specs.alt()) {
// ++size;
// if (num_zeros <= 0 && specs.type() != presentation_type::fixed)
// num_zeros = 0;
// if (num_zeros > 0) size += size_t(num_zeros);
// }
// auto grouping = Grouping(loc, specs.localized());
// size += size_t(grouping.count_separators(exp));
// return write_padded<Char, align::right>(out, specs, size, [&](iterator
// it) {
// if (s != sign::none) *it++ = detail::getsign<Char>(s);
// it = write_significand<Char>(it, significand, significand_size,
// f.exponent, grouping);
// if (!specs.alt()) return it;
// *it++ = decimal_point;
// return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
// });
// TODO
return nullptr;
if (is_negative) {
*buf++ = '-';
}
return write_significand_e(buf, significand, significand_size,
ret.exponent);
} else if (exp > 0) {
// 1234e-2 -> 12.34[0+]
// int num_zeros = specs.alt() ? spec_precision - significand_size : 0;
// size += 1 + static_cast<unsigned>(max_of(num_zeros, 0));
size += 1;
// auto grouping = Grouping(loc, specs.localized());
// size += size_t(grouping.count_separators(exp));
// return write_padded<Char, align::right>(out, specs, size, [&](iterator
// it) {
// if (s != sign::none) *it++ = detail::getsign<Char>(s);
// it = write_significand(it, significand, significand_size, exp,
// decimal_point, grouping);
// return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
// });
if (is_negative) {
*buf++ = '-';
}
return write_significand(buf, significand, significand_size, exp,
decimal_point);
}
// 1234e-6 -> 0.001234
int num_zeros = -exp;
// if (significand_size == 0 && specs.precision >= 0 &&
// specs.precision < num_zeros) {
// num_zeros = spec_precision;
// }
bool pointy = num_zeros != 0 || significand_size != 0; // || specs.alt();
size += 1u + (pointy ? 1u : 0u) + size_t(num_zeros);
// return write_padded<Char, align::right>(out, specs, size, [&](iterator it)
// {
// if (s != sign::none) *it++ = detail::getsign<Char>(s);
// *it++ = zero;
// if (!pointy) return it;
// *it++ = decimal_point;
// it = detail::fill_n(it, num_zeros, zero);
// return write_significand<Char>(it, significand, significand_size);
// });
if (is_negative) {
*buf++ = '-';
}
*buf++ = zero_char;
if (!pointy) return buf;
*buf++ = decimal_point;
buf = fill_n(buf, num_zeros, zero_char);
return format_decimal(buf, significand, significand_size);
}
#if 0
std::string print_floats(const std::vector<float> &v) {
char buffer[40];
char buffer[40]; // 25 should be enough
size_t n = v.size();
std::vector<char> dst;
@@ -268,9 +302,8 @@ std::string print_floats(const std::vector<float> &v) {
curr += 2;
}
char *e = jkj::dragonbox::to_chars(v[i], buffer);
char *e = write_float(v[i], buffer);
size_t len = e - buffer; // includes '\0'
std::cout << len << "\n";
// +2 for ', '
if ((curr + len + 2) >= dst.size()) {
@@ -285,7 +318,6 @@ std::string print_floats(const std::vector<float> &v) {
std::string s(dst.data(), curr);
return s;
}
#endif
#if 0
std::string print_floats(const std::vector<float> &v) {
@@ -323,10 +355,9 @@ std::string print_floats(const std::vector<float> &v) {
}
#endif
int main(int argc, char **argv)
{
int main(int argc, char** argv) {
bool delim_at_end = true;
size_t n = 1024*1024*16;
size_t n = 1024 * 1024 * 16;
if (argc > 1) {
n = std::stoi(argv[1]);
}
@@ -337,9 +368,10 @@ int main(int argc, char **argv)
double d = 1.0;
for (size_t i = 0; i < 32; i++) {
char buf[25];
//char *p = dtoa_milo(d, buf);
//*p = '\0';
//std::cout << buf << "\n";
char *p = write_float(d, buf);
*p = '\0';
std::cout << "db " << buf << "\n";
{
auto ret = jkj::dragonbox::to_decimal(d);
@@ -363,20 +395,21 @@ int main(int argc, char **argv)
}
d = d * 10.0;
}
std::vector<float> arr = gen_floats(n);
//std::cout << input << "\n";
std::vector<float> arr = gen_floats(n);
// std::cout << input << "\n";
auto start = std::chrono::steady_clock::now();
//std::string s = print_floats(arr);
//auto end = std::chrono::steady_clock::now();
std::string s = print_floats(arr);
auto end = std::chrono::steady_clock::now();
//std::cout << "n elems " << arr.size() << "\n";
std::cout << "n elems " << arr.size() << "\n";
//std::cout << "print : " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " [ms]\n";
std::cout << "print : " <<
std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< " [ms]\n";
//std::cout << s << "\n";

View File

@@ -1,10 +1,24 @@
// SPDX-License-Identifier: Apache 2.0
// Copyright 2023 - Present, Light Transport Entertainment, Inc.
#include <cmath>
#include "str-util.hh"
#include "unicode-xid.hh"
#include "common-macros.inc"
// external
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#endif
#include "external/dragonbox/dragonbox_to_chars.h"
#ifdef __clang__
#pragma clang diagnostic pop
#endif
namespace tinyusdz {
std::string buildEscapedAndQuotedStringForUSDA(const std::string &str) {
@@ -675,4 +689,285 @@ bool is_valid_utf8_identifier(const std::string &str) {
return true;
}
// ----------------------------------------------------------------------
// based on fmtlib
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
// MIT license.
//
namespace internal {
// TOOD: Use builtin_clz insturction?
// T = uint32 or uint64
template <typename T>
inline int count_digits(T n) {
int count = 1;
for (;;) {
// Integer division is slow so do it for a group of four digits instead
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
if (n < 10) return count;
if (n < 100) return count + 1;
if (n < 1000) return count + 2;
if (n < 10000) return count + 3;
n /= 10000u;
count += 4;
}
}
// Converts value in the range [0, 100) to a string.
// GCC generates slightly better code when value is pointer-size.
inline auto digits2(size_t value) -> const char* {
// Align data since unaligned access may be slower when crossing a
// hardware-specific boundary.
alignas(2) static const char data[] =
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
return &data[value * 2];
}
// Writes a two-digit value to out.
inline void write2digits(char* out, size_t value) {
// if (!is_constant_evaluated() && std::is_same<Char, char>::value &&
// !FMT_OPTIMIZE_SIZE) {
// memcpy(out, digits2(value), 2);
// return;
// }
*out++ = static_cast<char>('0' + value / 10);
*out = static_cast<char>('0' + value % 10);
}
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
static char* write_exponent(int exp, char* out) {
// FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range");
if (exp < 0) {
*out++ = '-';
exp = -exp;
} else {
*out++ = '+';
}
auto uexp = static_cast<uint32_t>(exp);
// if (is_constant_evaluated()) {
// if (uexp < 10) *out++ = '0';
// return format_decimal<Char>(out, uexp, count_digits(uexp));
// }
if (uexp >= 100u) {
const char* top = digits2(uexp / 100);
if (uexp >= 1000u) *out++ = top[0];
*out++ = static_cast<char>(top[1]);
uexp %= 100;
}
const char* d = digits2(uexp);
*out++ = static_cast<char>(d[0]);
*out++ = static_cast<char>(d[1]);
return out;
}
inline char* fill_n(char* p, int n, char c) {
for (int i = 0; i < n; i++, p++) {
*p = c;
}
return p;
}
inline void format_decimal_impl(char* out, uint64_t value, uint32_t size) {
// FMT_ASSERT(size >= count_digits(value), "invalid digit count");
unsigned n = size;
while (value >= 100) {
// Integer division is slow so do it for a group of two digits instead
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
n -= 2;
write2digits(out + n, static_cast<unsigned>(value % 100));
value /= 100;
}
if (value >= 10) {
n -= 2;
write2digits(out + n, static_cast<unsigned>(value));
} else {
out[--n] = static_cast<char>('0' + value);
}
//return out + n;
}
inline char* format_decimal(char* out, uint64_t value, uint32_t num_digits) {
format_decimal_impl(out, value, num_digits);
return out + num_digits;
}
inline char* write_significand_e(char* out, uint64_t significand,
int significand_size, int exponent) {
out = format_decimal(out, significand, uint32_t(significand_size));
return fill_n(out, exponent, '0');
}
inline char* write_significand(char* out, uint64_t significand,
int significand_size, int integral_size,
char decimal_point) {
if (!decimal_point) return format_decimal(out, significand, uint32_t(significand_size));
out += significand_size + 1;
char* end = out;
int floating_size = significand_size - integral_size;
for (int i = floating_size / 2; i > 0; --i) {
out -= 2;
write2digits(out, static_cast<std::size_t>(significand % 100));
significand /= 100;
}
if (floating_size % 2 != 0) {
*--out = static_cast<char>('0' + significand % 10);
significand /= 10;
}
*--out = decimal_point;
format_decimal(out - integral_size, significand, uint32_t(integral_size));
return end;
}
// Use dragonbox algorithm to print floating point value.
// Use to_deciamal and do human-readable pretty printing for some value range(e.g. print 1e-3 as 0.001)
//
// exp_upper: (15 + 1) for double, (6+1) for float
static char* dtoa_dragonbox(const double f, char* buf, int exp_upper = 16) {
//const int spec_precision = -1; // unlimited
bool is_negative = std::signbit(f);
auto ret = jkj::dragonbox::to_decimal(f);
// print human-readable float for the value in range [1e-exp_lower, 1e+exp_upper]
const int exp_lower = -4;
char exp_char = 'e';
char zero_char = '0';
auto significand = ret.significand;
int significand_size = count_digits(significand);
//size_t size = size_t(significand_size) + (is_negative ? 1u : 0u);
int output_exp = ret.exponent + significand_size - 1;
bool use_exp_format = (output_exp < exp_lower) || (output_exp >= exp_upper);
char decimal_point = '.';
if (use_exp_format) {
int num_zeros = 0;
if (significand_size == 1) {
decimal_point = '\0';
}
//auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp;
//int exp_digits = 2;
//if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3;
//size += (decimal_point ? 1u : 0u) + 2u + size_t(exp_digits);
if (is_negative) {
*buf++ = '-';
}
buf =
write_significand(buf, significand, significand_size, 1, decimal_point);
if (num_zeros > 0) buf = fill_n(buf, num_zeros, zero_char);
*buf++ = exp_char;
return write_exponent(output_exp, buf);
}
int exp = ret.exponent + significand_size;
if (ret.exponent >= 0) {
// 1234e5 -> 123400000[.0+]
//size += static_cast<size_t>(ret.exponent);
//int num_zeros = spec_precision - exp;
// abort_fuzzing_if(num_zeros > 5000);
// if (specs.alt()) {
// ++size;
// if (num_zeros <= 0 && specs.type() != presentation_type::fixed)
// num_zeros = 0;
// if (num_zeros > 0) size += size_t(num_zeros);
// }
// auto grouping = Grouping(loc, specs.localized());
// size += size_t(grouping.count_separators(exp));
// return write_padded<Char, align::right>(out, specs, size, [&](iterator
// it) {
// if (s != sign::none) *it++ = detail::getsign<Char>(s);
// it = write_significand<Char>(it, significand, significand_size,
// f.exponent, grouping);
// if (!specs.alt()) return it;
// *it++ = decimal_point;
// return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
// });
if (is_negative) {
*buf++ = '-';
}
return write_significand_e(buf, significand, significand_size,
ret.exponent);
} else if (exp > 0) {
// 1234e-2 -> 12.34[0+]
// int num_zeros = specs.alt() ? spec_precision - significand_size : 0;
// size += 1 + static_cast<unsigned>(max_of(num_zeros, 0));
//size += 1;
// auto grouping = Grouping(loc, specs.localized());
// size += size_t(grouping.count_separators(exp));
// return write_padded<Char, align::right>(out, specs, size, [&](iterator
// it) {
// if (s != sign::none) *it++ = detail::getsign<Char>(s);
// it = write_significand(it, significand, significand_size, exp,
// decimal_point, grouping);
// return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
// });
if (is_negative) {
*buf++ = '-';
}
return write_significand(buf, significand, significand_size, exp,
decimal_point);
}
// 1234e-6 -> 0.001234
int num_zeros = -exp;
// if (significand_size == 0 && specs.precision >= 0 &&
// specs.precision < num_zeros) {
// num_zeros = spec_precision;
// }
bool pointy = num_zeros != 0 || significand_size != 0; // || specs.alt();
//size += 1u + (pointy ? 1u : 0u) + size_t(num_zeros);
// return write_padded<Char, align::right>(out, specs, size, [&](iterator it)
// {
// if (s != sign::none) *it++ = detail::getsign<Char>(s);
// *it++ = zero;
// if (!pointy) return it;
// *it++ = decimal_point;
// it = detail::fill_n(it, num_zeros, zero);
// return write_significand<Char>(it, significand, significand_size);
// });
if (is_negative) {
*buf++ = '-';
}
*buf++ = zero_char;
if (!pointy) return buf;
*buf++ = decimal_point;
buf = fill_n(buf, num_zeros, zero_char);
return format_decimal(buf, significand, uint32_t(significand_size));
}
static char* dtoa_dragonbox(const float f, char* buf) {
return dtoa_dragonbox(double(f), buf, 7);
}
} // namespace internal
char *dtoa(float f, char *buffer) {
return internal::dtoa_dragonbox(f, buffer);
}
char *dtoa(double f, char *buffer) {
return internal::dtoa_dragonbox(f, buffer);
}
} // namespace tinyusdz

View File

@@ -387,6 +387,17 @@ inline std::string codepoint_to_utf8(uint32_t code) {
}
//
// float/double to string
// Currently tinyusdz uses dragonbox algorithm
//
// buffer must be at least 25 bytes.
// filled string is not null-terminated.
// (Use *(dtoa(f, buf)) = '\0' if you want null-terminated string)
//
char *dtoa(float f, char *buf);
char *dtoa(double f, char *buf);
#if 0 // TODO
///
/// Convert UTF-8 code to UTF-8 char