🔨 cleanup after #915
This commit is contained in:
parent
010e596001
commit
3cca630836
6 changed files with 521 additions and 385 deletions
1
Makefile
1
Makefile
|
@ -8,6 +8,7 @@ SRCS = develop/json.hpp \
|
||||||
develop/detail/exceptions.hpp \
|
develop/detail/exceptions.hpp \
|
||||||
develop/detail/value_t.hpp \
|
develop/detail/value_t.hpp \
|
||||||
develop/detail/conversions/from_json.hpp \
|
develop/detail/conversions/from_json.hpp \
|
||||||
|
develop/detail/conversions/to_chars.hpp \
|
||||||
develop/detail/conversions/to_json.hpp \
|
develop/detail/conversions/to_json.hpp \
|
||||||
develop/detail/parsing/input_adapters.hpp \
|
develop/detail/parsing/input_adapters.hpp \
|
||||||
develop/detail/parsing/lexer.hpp \
|
develop/detail/parsing/lexer.hpp \
|
||||||
|
|
|
@ -821,8 +821,6 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I
|
||||||
|
|
||||||
The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright © 2008-2009 [Björn Hoehrmann](http://bjoern.hoehrmann.de/) <bjoern@hoehrmann.de>
|
The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright © 2008-2009 [Björn Hoehrmann](http://bjoern.hoehrmann.de/) <bjoern@hoehrmann.de>
|
||||||
|
|
||||||
* * *
|
|
||||||
|
|
||||||
The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright © 2009 [Florian Loitsch](http://florian.loitsch.com/)
|
The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright © 2009 [Florian Loitsch](http://florian.loitsch.com/)
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
|
@ -934,6 +932,7 @@ I deeply appreciate the help of the following people.
|
||||||
- [Matthias Möller](https://github.com/TinyTinni) added a `.natvis` for the MSVC debug view.
|
- [Matthias Möller](https://github.com/TinyTinni) added a `.natvis` for the MSVC debug view.
|
||||||
- [bogemic](https://github.com/bogemic) fixed some C++17 deprecation warnings.
|
- [bogemic](https://github.com/bogemic) fixed some C++17 deprecation warnings.
|
||||||
- [Eren Okka](https://github.com/erengy) fixed some MSVC warnings.
|
- [Eren Okka](https://github.com/erengy) fixed some MSVC warnings.
|
||||||
|
- [abolz](https://github.com/abolz) integrated the Grisu2 algorithm for proper floating-point formatting, allowing more roundtrip checks to succeed.
|
||||||
|
|
||||||
|
|
||||||
Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.
|
Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.
|
||||||
|
|
|
@ -11,24 +11,30 @@ namespace nlohmann
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
// Implements the Grisu2 algorithm for binary to decimal floating-point conversion.
|
/*!
|
||||||
//
|
@brief implements the Grisu2 algorithm for binary to decimal floating-point
|
||||||
// This implementation is a slightly modified version of the reference implementation which may be
|
conversion.
|
||||||
// obtained from http://florian.loitsch.com/publications (bench.tar.gz).
|
|
||||||
//
|
This implementation is a slightly modified version of the reference
|
||||||
// The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.
|
implementation which may be obtained from
|
||||||
//
|
http://florian.loitsch.com/publications (bench.tar.gz).
|
||||||
// For a detailed description of the algorithm see:
|
|
||||||
//
|
The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.
|
||||||
// [1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with Integers",
|
|
||||||
// Proceedings of the ACM SIGPLAN 2010 Conference on Programming Language Design and Implementation, PLDI 2010
|
For a detailed description of the algorithm see:
|
||||||
// [2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately",
|
|
||||||
// Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation, PLDI 1996
|
[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with
|
||||||
|
Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming
|
||||||
|
Language Design and Implementation, PLDI 2010
|
||||||
|
[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately",
|
||||||
|
Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language
|
||||||
|
Design and Implementation, PLDI 1996
|
||||||
|
*/
|
||||||
namespace dtoa_impl
|
namespace dtoa_impl
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename Target, typename Source>
|
template <typename Target, typename Source>
|
||||||
Target reinterpret_bits(Source source)
|
Target reinterpret_bits(const Source source)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(Target) == sizeof(Source), "size mismatch");
|
static_assert(sizeof(Target) == sizeof(Source), "size mismatch");
|
||||||
|
|
||||||
|
@ -44,36 +50,27 @@ struct diyfp // f * 2^e
|
||||||
uint64_t f;
|
uint64_t f;
|
||||||
int e;
|
int e;
|
||||||
|
|
||||||
constexpr diyfp() : f(0), e(0) {}
|
constexpr diyfp() noexcept : f(0), e(0) {}
|
||||||
constexpr diyfp(uint64_t f_, int e_) : f(f_), e(e_) {}
|
constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {}
|
||||||
|
|
||||||
// Returns x - y.
|
/*!
|
||||||
// PRE: x.e == y.e and x.f >= y.f
|
@brief returns x - y
|
||||||
static diyfp sub(diyfp x, diyfp y);
|
@pre x.e == y.e and x.f >= y.f
|
||||||
|
*/
|
||||||
// Returns x * y.
|
static diyfp sub(const diyfp& x, const diyfp& y) noexcept
|
||||||
// The result is rounded. (Only the upper q bits are returned.)
|
{
|
||||||
static diyfp mul(diyfp x, diyfp y);
|
|
||||||
|
|
||||||
// Normalize x such that the significand is >= 2^(q-1).
|
|
||||||
// PRE: x.f != 0
|
|
||||||
static diyfp normalize(diyfp x);
|
|
||||||
|
|
||||||
// Normalize x such that the result has the exponent E.
|
|
||||||
// PRE: e >= x.e and the upper e - x.e bits of x.f must be zero.
|
|
||||||
static diyfp normalize_to(diyfp x, int e);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline diyfp diyfp::sub(diyfp x, diyfp y)
|
|
||||||
{
|
|
||||||
assert(x.e == y.e);
|
assert(x.e == y.e);
|
||||||
assert(x.f >= y.f);
|
assert(x.f >= y.f);
|
||||||
|
|
||||||
return diyfp(x.f - y.f, x.e);
|
return diyfp(x.f - y.f, x.e);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline diyfp diyfp::mul(diyfp x, diyfp y)
|
/*!
|
||||||
{
|
@brief returns x * y
|
||||||
|
@note The result is rounded. (Only the upper q bits are returned.)
|
||||||
|
*/
|
||||||
|
static diyfp mul(const diyfp& x, const diyfp& y) noexcept
|
||||||
|
{
|
||||||
static_assert(kPrecision == 64, "internal error");
|
static_assert(kPrecision == 64, "internal error");
|
||||||
|
|
||||||
// Computes:
|
// Computes:
|
||||||
|
@ -131,10 +128,14 @@ inline diyfp diyfp::mul(diyfp x, diyfp y)
|
||||||
const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32);
|
const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32);
|
||||||
|
|
||||||
return diyfp(h, x.e + y.e + 64);
|
return diyfp(h, x.e + y.e + 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline diyfp diyfp::normalize(diyfp x)
|
/*!
|
||||||
{
|
@brief normalize x such that the significand is >= 2^(q-1)
|
||||||
|
@pre x.f != 0
|
||||||
|
*/
|
||||||
|
static diyfp normalize(diyfp x) noexcept
|
||||||
|
{
|
||||||
assert(x.f != 0);
|
assert(x.f != 0);
|
||||||
|
|
||||||
while ((x.f >> 63) == 0)
|
while ((x.f >> 63) == 0)
|
||||||
|
@ -144,17 +145,22 @@ inline diyfp diyfp::normalize(diyfp x)
|
||||||
}
|
}
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline diyfp diyfp::normalize_to(diyfp x, int target_exponent)
|
/*!
|
||||||
{
|
@brief normalize x such that the result has the exponent E
|
||||||
|
@pre e >= x.e and the upper e - x.e bits of x.f must be zero.
|
||||||
|
*/
|
||||||
|
static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept
|
||||||
|
{
|
||||||
const int delta = x.e - target_exponent;
|
const int delta = x.e - target_exponent;
|
||||||
|
|
||||||
assert(delta >= 0);
|
assert(delta >= 0);
|
||||||
assert(((x.f << delta) >> delta) == x.f);
|
assert(((x.f << delta) >> delta) == x.f);
|
||||||
|
|
||||||
return diyfp(x.f << delta, target_exponent);
|
return diyfp(x.f << delta, target_exponent);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct boundaries
|
struct boundaries
|
||||||
{
|
{
|
||||||
|
@ -163,8 +169,12 @@ struct boundaries
|
||||||
diyfp plus;
|
diyfp plus;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Compute the (normalized) diyfp representing the input number 'value' and its boundaries.
|
/*!
|
||||||
// PRE: value must be finite and positive
|
Compute the (normalized) diyfp representing the input number 'value' and its
|
||||||
|
boundaries.
|
||||||
|
|
||||||
|
@pre value must be finite and positive
|
||||||
|
*/
|
||||||
template <typename FloatType>
|
template <typename FloatType>
|
||||||
boundaries compute_boundaries(FloatType value)
|
boundaries compute_boundaries(FloatType value)
|
||||||
{
|
{
|
||||||
|
@ -193,9 +203,7 @@ boundaries compute_boundaries(FloatType value)
|
||||||
const uint64_t F = bits & (kHiddenBit - 1);
|
const uint64_t F = bits & (kHiddenBit - 1);
|
||||||
|
|
||||||
const bool is_denormal = (E == 0);
|
const bool is_denormal = (E == 0);
|
||||||
|
const diyfp v = is_denormal
|
||||||
const diyfp v
|
|
||||||
= is_denormal
|
|
||||||
? diyfp(F, 1 - kBias)
|
? diyfp(F, 1 - kBias)
|
||||||
: diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);
|
: diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);
|
||||||
|
|
||||||
|
@ -221,10 +229,8 @@ boundaries compute_boundaries(FloatType value)
|
||||||
// v- m- v m+ v+
|
// v- m- v m+ v+
|
||||||
|
|
||||||
const bool lower_boundary_is_closer = (F == 0 and E > 1);
|
const bool lower_boundary_is_closer = (F == 0 and E > 1);
|
||||||
|
|
||||||
const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);
|
const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);
|
||||||
const diyfp m_minus
|
const diyfp m_minus = lower_boundary_is_closer
|
||||||
= lower_boundary_is_closer
|
|
||||||
? diyfp(4 * v.f - 1, v.e - 2) // (B)
|
? diyfp(4 * v.f - 1, v.e - 2) // (B)
|
||||||
: diyfp(2 * v.f - 1, v.e - 1); // (A)
|
: diyfp(2 * v.f - 1, v.e - 1); // (A)
|
||||||
|
|
||||||
|
@ -302,12 +308,13 @@ struct cached_power // c = f * 2^e ~= 10^k
|
||||||
int k;
|
int k;
|
||||||
};
|
};
|
||||||
|
|
||||||
// For a normalized diyfp w = f * 2^e, this function returns a (normalized)
|
/*!
|
||||||
// cached power-of-ten c = f_c * 2^e_c, such that the exponent of the product
|
For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached
|
||||||
// w * c satisfies (Definition 3.2 from [1])
|
power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c
|
||||||
//
|
satisfies (Definition 3.2 from [1])
|
||||||
// alpha <= e_c + e + q <= gamma.
|
|
||||||
//
|
alpha <= e_c + e + q <= gamma.
|
||||||
|
*/
|
||||||
inline cached_power get_cached_power_for_binary_exponent(int e)
|
inline cached_power get_cached_power_for_binary_exponent(int e)
|
||||||
{
|
{
|
||||||
// Now
|
// Now
|
||||||
|
@ -468,24 +475,66 @@ inline cached_power get_cached_power_for_binary_exponent(int e)
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.
|
/*!
|
||||||
// For n == 0, returns 1 and sets pow10 := 1.
|
For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.
|
||||||
inline int find_largest_pow10(uint32_t n, uint32_t& pow10)
|
For n == 0, returns 1 and sets pow10 := 1.
|
||||||
|
*/
|
||||||
|
inline int find_largest_pow10(const uint32_t n, uint32_t& pow10)
|
||||||
{
|
{
|
||||||
if (n >= 1000000000) { pow10 = 1000000000; return 10; }
|
if (n >= 1000000000)
|
||||||
if (n >= 100000000) { pow10 = 100000000; return 9; }
|
{
|
||||||
if (n >= 10000000) { pow10 = 10000000; return 8; }
|
pow10 = 1000000000;
|
||||||
if (n >= 1000000) { pow10 = 1000000; return 7; }
|
return 10;
|
||||||
if (n >= 100000) { pow10 = 100000; return 6; }
|
}
|
||||||
if (n >= 10000) { pow10 = 10000; return 5; }
|
else if (n >= 100000000)
|
||||||
if (n >= 1000) { pow10 = 1000; return 4; }
|
{
|
||||||
if (n >= 100) { pow10 = 100; return 3; }
|
pow10 = 100000000;
|
||||||
if (n >= 10) { pow10 = 10; return 2; }
|
return 9;
|
||||||
|
}
|
||||||
pow10 = 1; return 1;
|
else if (n >= 10000000)
|
||||||
|
{
|
||||||
|
pow10 = 10000000;
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
else if (n >= 1000000)
|
||||||
|
{
|
||||||
|
pow10 = 1000000;
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
else if (n >= 100000)
|
||||||
|
{
|
||||||
|
pow10 = 100000;
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
else if (n >= 10000)
|
||||||
|
{
|
||||||
|
pow10 = 10000;
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
else if (n >= 1000)
|
||||||
|
{
|
||||||
|
pow10 = 1000;
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
else if (n >= 100)
|
||||||
|
{
|
||||||
|
pow10 = 100;
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
else if (n >= 10)
|
||||||
|
{
|
||||||
|
pow10 = 10;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pow10 = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta, uint64_t rest, uint64_t ten_k)
|
inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta,
|
||||||
|
uint64_t rest, uint64_t ten_k)
|
||||||
{
|
{
|
||||||
assert(len >= 1);
|
assert(len >= 1);
|
||||||
assert(dist <= delta);
|
assert(dist <= delta);
|
||||||
|
@ -521,9 +570,12 @@ inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta, uint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.
|
/*!
|
||||||
// M- and M+ must be normalized and share the same exponent -60 <= e <= -32.
|
Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.
|
||||||
inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, diyfp M_minus, diyfp w, diyfp M_plus)
|
M- and M+ must be normalized and share the same exponent -60 <= e <= -32.
|
||||||
|
*/
|
||||||
|
inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
|
||||||
|
diyfp M_minus, diyfp w, diyfp M_plus)
|
||||||
{
|
{
|
||||||
static_assert(kAlpha >= -60, "internal error");
|
static_assert(kAlpha >= -60, "internal error");
|
||||||
static_assert(kGamma <= -32, "internal error");
|
static_assert(kGamma <= -32, "internal error");
|
||||||
|
@ -757,10 +809,13 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, d
|
||||||
// N = 9 for p = 24 (IEEE single precision)
|
// N = 9 for p = 24 (IEEE single precision)
|
||||||
}
|
}
|
||||||
|
|
||||||
// v = buf * 10^decimal_exponent
|
/*!
|
||||||
// len is the length of the buffer (number of decimal digits)
|
v = buf * 10^decimal_exponent
|
||||||
// The buffer must be large enough, i.e. >= max_digits10.
|
len is the length of the buffer (number of decimal digits)
|
||||||
inline void grisu2(char* buf, int& len, int& decimal_exponent, diyfp m_minus, diyfp v, diyfp m_plus)
|
The buffer must be large enough, i.e. >= max_digits10.
|
||||||
|
*/
|
||||||
|
inline void grisu2(char* buf, int& len, int& decimal_exponent,
|
||||||
|
diyfp m_minus, diyfp v, diyfp m_plus)
|
||||||
{
|
{
|
||||||
assert(m_plus.e == m_minus.e);
|
assert(m_plus.e == m_minus.e);
|
||||||
assert(m_plus.e == v.e);
|
assert(m_plus.e == v.e);
|
||||||
|
@ -812,9 +867,11 @@ inline void grisu2(char* buf, int& len, int& decimal_exponent, diyfp m_minus, di
|
||||||
grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);
|
grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// v = buf * 10^decimal_exponent
|
/*!
|
||||||
// len is the length of the buffer (number of decimal digits)
|
v = buf * 10^decimal_exponent
|
||||||
// The buffer must be large enough, i.e. >= max_digits10.
|
len is the length of the buffer (number of decimal digits)
|
||||||
|
The buffer must be large enough, i.e. >= max_digits10.
|
||||||
|
*/
|
||||||
template <typename FloatType>
|
template <typename FloatType>
|
||||||
void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
|
void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
|
||||||
{
|
{
|
||||||
|
@ -849,9 +906,11 @@ void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
|
||||||
grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);
|
grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends a decimal representation of e to buf.
|
/*!
|
||||||
// Returns a pointer to the element following the exponent.
|
@brief appends a decimal representation of e to buf
|
||||||
// PRE: -1000 < e < 1000
|
@return a pointer to the element following the exponent.
|
||||||
|
@pre -1000 < e < 1000
|
||||||
|
*/
|
||||||
inline char* append_exponent(char* buf, int e)
|
inline char* append_exponent(char* buf, int e)
|
||||||
{
|
{
|
||||||
assert(e > -1000);
|
assert(e > -1000);
|
||||||
|
@ -893,12 +952,17 @@ inline char* append_exponent(char* buf, int e)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prettify v = buf * 10^decimal_exponent
|
/*!
|
||||||
// If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point notation.
|
@brief prettify v = buf * 10^decimal_exponent
|
||||||
// Otherwise it will be printed in exponential notation.
|
|
||||||
// PRE: min_exp < 0
|
If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point
|
||||||
// PRE: max_exp > 0
|
notation. Otherwise it will be printed in exponential notation.
|
||||||
inline char* format_buffer(char* buf, int len, int decimal_exponent, int min_exp, int max_exp)
|
|
||||||
|
@pre min_exp < 0
|
||||||
|
@pre max_exp > 0
|
||||||
|
*/
|
||||||
|
inline char* format_buffer(char* buf, int len, int decimal_exponent,
|
||||||
|
int min_exp, int max_exp)
|
||||||
{
|
{
|
||||||
assert(min_exp < 0);
|
assert(min_exp < 0);
|
||||||
assert(max_exp > 0);
|
assert(max_exp > 0);
|
||||||
|
@ -969,14 +1033,16 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent, int min_exp
|
||||||
|
|
||||||
} // namespace dtoa_impl
|
} // namespace dtoa_impl
|
||||||
|
|
||||||
// Generates a decimal representation of the floating-point number value in [first, last).
|
/*!
|
||||||
//
|
@brief generates a decimal representation of the floating-point number value in [first, last).
|
||||||
// The format of the resulting decimal representation is similar to printf's %g format.
|
|
||||||
// Returns an iterator pointing past-the-end of the decimal representation.
|
The format of the resulting decimal representation is similar to printf's %g
|
||||||
//
|
format. Returns an iterator pointing past-the-end of the decimal representation.
|
||||||
// Note: The input number must be finite, i.e. NaN's and Inf's are not supported.
|
|
||||||
// Note: The buffer must be large enough.
|
@note The input number must be finite, i.e. NaN's and Inf's are not supported.
|
||||||
// Note: The result is NOT null-terminated.
|
@note The buffer must be large enough.
|
||||||
|
@note The result is NOT null-terminated.
|
||||||
|
*/
|
||||||
template <typename FloatType>
|
template <typename FloatType>
|
||||||
char* to_chars(char* first, char* last, FloatType value)
|
char* to_chars(char* first, char* last, FloatType value)
|
||||||
{
|
{
|
||||||
|
|
|
@ -483,8 +483,8 @@ class serializer
|
||||||
}
|
}
|
||||||
|
|
||||||
// If number_float_t is an IEEE-754 single or double precision number,
|
// If number_float_t is an IEEE-754 single or double precision number,
|
||||||
// use the Grisu2 algorithm to produce short numbers which are guaranteed
|
// use the Grisu2 algorithm to produce short numbers which are
|
||||||
// to round-trip, using strtof and strtod, resp.
|
// guaranteed to round-trip, using strtof and strtod, resp.
|
||||||
//
|
//
|
||||||
// NB: The test below works if <long double> == <double>.
|
// NB: The test below works if <long double> == <double>.
|
||||||
static constexpr bool is_ieee_single_or_double
|
static constexpr bool is_ieee_single_or_double
|
||||||
|
|
272
src/json.hpp
272
src/json.hpp
|
@ -7077,24 +7077,30 @@ namespace nlohmann
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
// Implements the Grisu2 algorithm for binary to decimal floating-point conversion.
|
/*!
|
||||||
//
|
@brief implements the Grisu2 algorithm for binary to decimal floating-point
|
||||||
// This implementation is a slightly modified version of the reference implementation which may be
|
conversion.
|
||||||
// obtained from http://florian.loitsch.com/publications (bench.tar.gz).
|
|
||||||
//
|
This implementation is a slightly modified version of the reference
|
||||||
// The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.
|
implementation which may be obtained from
|
||||||
//
|
http://florian.loitsch.com/publications (bench.tar.gz).
|
||||||
// For a detailed description of the algorithm see:
|
|
||||||
//
|
The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.
|
||||||
// [1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with Integers",
|
|
||||||
// Proceedings of the ACM SIGPLAN 2010 Conference on Programming Language Design and Implementation, PLDI 2010
|
For a detailed description of the algorithm see:
|
||||||
// [2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately",
|
|
||||||
// Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation, PLDI 1996
|
[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with
|
||||||
|
Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming
|
||||||
|
Language Design and Implementation, PLDI 2010
|
||||||
|
[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately",
|
||||||
|
Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language
|
||||||
|
Design and Implementation, PLDI 1996
|
||||||
|
*/
|
||||||
namespace dtoa_impl
|
namespace dtoa_impl
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename Target, typename Source>
|
template <typename Target, typename Source>
|
||||||
Target reinterpret_bits(Source source)
|
Target reinterpret_bits(const Source source)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(Target) == sizeof(Source), "size mismatch");
|
static_assert(sizeof(Target) == sizeof(Source), "size mismatch");
|
||||||
|
|
||||||
|
@ -7110,36 +7116,27 @@ struct diyfp // f * 2^e
|
||||||
uint64_t f;
|
uint64_t f;
|
||||||
int e;
|
int e;
|
||||||
|
|
||||||
constexpr diyfp() : f(0), e(0) {}
|
constexpr diyfp() noexcept : f(0), e(0) {}
|
||||||
constexpr diyfp(uint64_t f_, int e_) : f(f_), e(e_) {}
|
constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {}
|
||||||
|
|
||||||
// Returns x - y.
|
/*!
|
||||||
// PRE: x.e == y.e and x.f >= y.f
|
@brief returns x - y
|
||||||
static diyfp sub(diyfp x, diyfp y);
|
@pre x.e == y.e and x.f >= y.f
|
||||||
|
*/
|
||||||
// Returns x * y.
|
static diyfp sub(const diyfp& x, const diyfp& y) noexcept
|
||||||
// The result is rounded. (Only the upper q bits are returned.)
|
{
|
||||||
static diyfp mul(diyfp x, diyfp y);
|
|
||||||
|
|
||||||
// Normalize x such that the significand is >= 2^(q-1).
|
|
||||||
// PRE: x.f != 0
|
|
||||||
static diyfp normalize(diyfp x);
|
|
||||||
|
|
||||||
// Normalize x such that the result has the exponent E.
|
|
||||||
// PRE: e >= x.e and the upper e - x.e bits of x.f must be zero.
|
|
||||||
static diyfp normalize_to(diyfp x, int e);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline diyfp diyfp::sub(diyfp x, diyfp y)
|
|
||||||
{
|
|
||||||
assert(x.e == y.e);
|
assert(x.e == y.e);
|
||||||
assert(x.f >= y.f);
|
assert(x.f >= y.f);
|
||||||
|
|
||||||
return diyfp(x.f - y.f, x.e);
|
return diyfp(x.f - y.f, x.e);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline diyfp diyfp::mul(diyfp x, diyfp y)
|
/*!
|
||||||
{
|
@brief returns x * y
|
||||||
|
@note The result is rounded. (Only the upper q bits are returned.)
|
||||||
|
*/
|
||||||
|
static diyfp mul(const diyfp& x, const diyfp& y) noexcept
|
||||||
|
{
|
||||||
static_assert(kPrecision == 64, "internal error");
|
static_assert(kPrecision == 64, "internal error");
|
||||||
|
|
||||||
// Computes:
|
// Computes:
|
||||||
|
@ -7197,10 +7194,14 @@ inline diyfp diyfp::mul(diyfp x, diyfp y)
|
||||||
const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32);
|
const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32);
|
||||||
|
|
||||||
return diyfp(h, x.e + y.e + 64);
|
return diyfp(h, x.e + y.e + 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline diyfp diyfp::normalize(diyfp x)
|
/*!
|
||||||
{
|
@brief normalize x such that the significand is >= 2^(q-1)
|
||||||
|
@pre x.f != 0
|
||||||
|
*/
|
||||||
|
static diyfp normalize(diyfp x) noexcept
|
||||||
|
{
|
||||||
assert(x.f != 0);
|
assert(x.f != 0);
|
||||||
|
|
||||||
while ((x.f >> 63) == 0)
|
while ((x.f >> 63) == 0)
|
||||||
|
@ -7210,17 +7211,22 @@ inline diyfp diyfp::normalize(diyfp x)
|
||||||
}
|
}
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline diyfp diyfp::normalize_to(diyfp x, int target_exponent)
|
/*!
|
||||||
{
|
@brief normalize x such that the result has the exponent E
|
||||||
|
@pre e >= x.e and the upper e - x.e bits of x.f must be zero.
|
||||||
|
*/
|
||||||
|
static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept
|
||||||
|
{
|
||||||
const int delta = x.e - target_exponent;
|
const int delta = x.e - target_exponent;
|
||||||
|
|
||||||
assert(delta >= 0);
|
assert(delta >= 0);
|
||||||
assert(((x.f << delta) >> delta) == x.f);
|
assert(((x.f << delta) >> delta) == x.f);
|
||||||
|
|
||||||
return diyfp(x.f << delta, target_exponent);
|
return diyfp(x.f << delta, target_exponent);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct boundaries
|
struct boundaries
|
||||||
{
|
{
|
||||||
|
@ -7229,8 +7235,12 @@ struct boundaries
|
||||||
diyfp plus;
|
diyfp plus;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Compute the (normalized) diyfp representing the input number 'value' and its boundaries.
|
/*!
|
||||||
// PRE: value must be finite and positive
|
Compute the (normalized) diyfp representing the input number 'value' and its
|
||||||
|
boundaries.
|
||||||
|
|
||||||
|
@pre value must be finite and positive
|
||||||
|
*/
|
||||||
template <typename FloatType>
|
template <typename FloatType>
|
||||||
boundaries compute_boundaries(FloatType value)
|
boundaries compute_boundaries(FloatType value)
|
||||||
{
|
{
|
||||||
|
@ -7259,9 +7269,7 @@ boundaries compute_boundaries(FloatType value)
|
||||||
const uint64_t F = bits & (kHiddenBit - 1);
|
const uint64_t F = bits & (kHiddenBit - 1);
|
||||||
|
|
||||||
const bool is_denormal = (E == 0);
|
const bool is_denormal = (E == 0);
|
||||||
|
const diyfp v = is_denormal
|
||||||
const diyfp v
|
|
||||||
= is_denormal
|
|
||||||
? diyfp(F, 1 - kBias)
|
? diyfp(F, 1 - kBias)
|
||||||
: diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);
|
: diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);
|
||||||
|
|
||||||
|
@ -7287,10 +7295,8 @@ boundaries compute_boundaries(FloatType value)
|
||||||
// v- m- v m+ v+
|
// v- m- v m+ v+
|
||||||
|
|
||||||
const bool lower_boundary_is_closer = (F == 0 and E > 1);
|
const bool lower_boundary_is_closer = (F == 0 and E > 1);
|
||||||
|
|
||||||
const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);
|
const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);
|
||||||
const diyfp m_minus
|
const diyfp m_minus = lower_boundary_is_closer
|
||||||
= lower_boundary_is_closer
|
|
||||||
? diyfp(4 * v.f - 1, v.e - 2) // (B)
|
? diyfp(4 * v.f - 1, v.e - 2) // (B)
|
||||||
: diyfp(2 * v.f - 1, v.e - 1); // (A)
|
: diyfp(2 * v.f - 1, v.e - 1); // (A)
|
||||||
|
|
||||||
|
@ -7368,12 +7374,13 @@ struct cached_power // c = f * 2^e ~= 10^k
|
||||||
int k;
|
int k;
|
||||||
};
|
};
|
||||||
|
|
||||||
// For a normalized diyfp w = f * 2^e, this function returns a (normalized)
|
/*!
|
||||||
// cached power-of-ten c = f_c * 2^e_c, such that the exponent of the product
|
For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached
|
||||||
// w * c satisfies (Definition 3.2 from [1])
|
power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c
|
||||||
//
|
satisfies (Definition 3.2 from [1])
|
||||||
// alpha <= e_c + e + q <= gamma.
|
|
||||||
//
|
alpha <= e_c + e + q <= gamma.
|
||||||
|
*/
|
||||||
inline cached_power get_cached_power_for_binary_exponent(int e)
|
inline cached_power get_cached_power_for_binary_exponent(int e)
|
||||||
{
|
{
|
||||||
// Now
|
// Now
|
||||||
|
@ -7534,24 +7541,66 @@ inline cached_power get_cached_power_for_binary_exponent(int e)
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.
|
/*!
|
||||||
// For n == 0, returns 1 and sets pow10 := 1.
|
For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.
|
||||||
inline int find_largest_pow10(uint32_t n, uint32_t& pow10)
|
For n == 0, returns 1 and sets pow10 := 1.
|
||||||
|
*/
|
||||||
|
inline int find_largest_pow10(const uint32_t n, uint32_t& pow10)
|
||||||
{
|
{
|
||||||
if (n >= 1000000000) { pow10 = 1000000000; return 10; }
|
if (n >= 1000000000)
|
||||||
if (n >= 100000000) { pow10 = 100000000; return 9; }
|
{
|
||||||
if (n >= 10000000) { pow10 = 10000000; return 8; }
|
pow10 = 1000000000;
|
||||||
if (n >= 1000000) { pow10 = 1000000; return 7; }
|
return 10;
|
||||||
if (n >= 100000) { pow10 = 100000; return 6; }
|
}
|
||||||
if (n >= 10000) { pow10 = 10000; return 5; }
|
else if (n >= 100000000)
|
||||||
if (n >= 1000) { pow10 = 1000; return 4; }
|
{
|
||||||
if (n >= 100) { pow10 = 100; return 3; }
|
pow10 = 100000000;
|
||||||
if (n >= 10) { pow10 = 10; return 2; }
|
return 9;
|
||||||
|
}
|
||||||
pow10 = 1; return 1;
|
else if (n >= 10000000)
|
||||||
|
{
|
||||||
|
pow10 = 10000000;
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
else if (n >= 1000000)
|
||||||
|
{
|
||||||
|
pow10 = 1000000;
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
else if (n >= 100000)
|
||||||
|
{
|
||||||
|
pow10 = 100000;
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
else if (n >= 10000)
|
||||||
|
{
|
||||||
|
pow10 = 10000;
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
else if (n >= 1000)
|
||||||
|
{
|
||||||
|
pow10 = 1000;
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
else if (n >= 100)
|
||||||
|
{
|
||||||
|
pow10 = 100;
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
else if (n >= 10)
|
||||||
|
{
|
||||||
|
pow10 = 10;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pow10 = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta, uint64_t rest, uint64_t ten_k)
|
inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta,
|
||||||
|
uint64_t rest, uint64_t ten_k)
|
||||||
{
|
{
|
||||||
assert(len >= 1);
|
assert(len >= 1);
|
||||||
assert(dist <= delta);
|
assert(dist <= delta);
|
||||||
|
@ -7587,9 +7636,12 @@ inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta, uint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.
|
/*!
|
||||||
// M- and M+ must be normalized and share the same exponent -60 <= e <= -32.
|
Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.
|
||||||
inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, diyfp M_minus, diyfp w, diyfp M_plus)
|
M- and M+ must be normalized and share the same exponent -60 <= e <= -32.
|
||||||
|
*/
|
||||||
|
inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
|
||||||
|
diyfp M_minus, diyfp w, diyfp M_plus)
|
||||||
{
|
{
|
||||||
static_assert(kAlpha >= -60, "internal error");
|
static_assert(kAlpha >= -60, "internal error");
|
||||||
static_assert(kGamma <= -32, "internal error");
|
static_assert(kGamma <= -32, "internal error");
|
||||||
|
@ -7823,10 +7875,13 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, d
|
||||||
// N = 9 for p = 24 (IEEE single precision)
|
// N = 9 for p = 24 (IEEE single precision)
|
||||||
}
|
}
|
||||||
|
|
||||||
// v = buf * 10^decimal_exponent
|
/*!
|
||||||
// len is the length of the buffer (number of decimal digits)
|
v = buf * 10^decimal_exponent
|
||||||
// The buffer must be large enough, i.e. >= max_digits10.
|
len is the length of the buffer (number of decimal digits)
|
||||||
inline void grisu2(char* buf, int& len, int& decimal_exponent, diyfp m_minus, diyfp v, diyfp m_plus)
|
The buffer must be large enough, i.e. >= max_digits10.
|
||||||
|
*/
|
||||||
|
inline void grisu2(char* buf, int& len, int& decimal_exponent,
|
||||||
|
diyfp m_minus, diyfp v, diyfp m_plus)
|
||||||
{
|
{
|
||||||
assert(m_plus.e == m_minus.e);
|
assert(m_plus.e == m_minus.e);
|
||||||
assert(m_plus.e == v.e);
|
assert(m_plus.e == v.e);
|
||||||
|
@ -7878,9 +7933,11 @@ inline void grisu2(char* buf, int& len, int& decimal_exponent, diyfp m_minus, di
|
||||||
grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);
|
grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// v = buf * 10^decimal_exponent
|
/*!
|
||||||
// len is the length of the buffer (number of decimal digits)
|
v = buf * 10^decimal_exponent
|
||||||
// The buffer must be large enough, i.e. >= max_digits10.
|
len is the length of the buffer (number of decimal digits)
|
||||||
|
The buffer must be large enough, i.e. >= max_digits10.
|
||||||
|
*/
|
||||||
template <typename FloatType>
|
template <typename FloatType>
|
||||||
void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
|
void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
|
||||||
{
|
{
|
||||||
|
@ -7915,9 +7972,11 @@ void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
|
||||||
grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);
|
grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends a decimal representation of e to buf.
|
/*!
|
||||||
// Returns a pointer to the element following the exponent.
|
@brief appends a decimal representation of e to buf
|
||||||
// PRE: -1000 < e < 1000
|
@return a pointer to the element following the exponent.
|
||||||
|
@pre -1000 < e < 1000
|
||||||
|
*/
|
||||||
inline char* append_exponent(char* buf, int e)
|
inline char* append_exponent(char* buf, int e)
|
||||||
{
|
{
|
||||||
assert(e > -1000);
|
assert(e > -1000);
|
||||||
|
@ -7959,12 +8018,17 @@ inline char* append_exponent(char* buf, int e)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prettify v = buf * 10^decimal_exponent
|
/*!
|
||||||
// If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point notation.
|
@brief prettify v = buf * 10^decimal_exponent
|
||||||
// Otherwise it will be printed in exponential notation.
|
|
||||||
// PRE: min_exp < 0
|
If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point
|
||||||
// PRE: max_exp > 0
|
notation. Otherwise it will be printed in exponential notation.
|
||||||
inline char* format_buffer(char* buf, int len, int decimal_exponent, int min_exp, int max_exp)
|
|
||||||
|
@pre min_exp < 0
|
||||||
|
@pre max_exp > 0
|
||||||
|
*/
|
||||||
|
inline char* format_buffer(char* buf, int len, int decimal_exponent,
|
||||||
|
int min_exp, int max_exp)
|
||||||
{
|
{
|
||||||
assert(min_exp < 0);
|
assert(min_exp < 0);
|
||||||
assert(max_exp > 0);
|
assert(max_exp > 0);
|
||||||
|
@ -8035,14 +8099,16 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent, int min_exp
|
||||||
|
|
||||||
} // namespace dtoa_impl
|
} // namespace dtoa_impl
|
||||||
|
|
||||||
// Generates a decimal representation of the floating-point number value in [first, last).
|
/*!
|
||||||
//
|
@brief generates a decimal representation of the floating-point number value in [first, last).
|
||||||
// The format of the resulting decimal representation is similar to printf's %g format.
|
|
||||||
// Returns an iterator pointing past-the-end of the decimal representation.
|
The format of the resulting decimal representation is similar to printf's %g
|
||||||
//
|
format. Returns an iterator pointing past-the-end of the decimal representation.
|
||||||
// Note: The input number must be finite, i.e. NaN's and Inf's are not supported.
|
|
||||||
// Note: The buffer must be large enough.
|
@note The input number must be finite, i.e. NaN's and Inf's are not supported.
|
||||||
// Note: The result is NOT null-terminated.
|
@note The buffer must be large enough.
|
||||||
|
@note The result is NOT null-terminated.
|
||||||
|
*/
|
||||||
template <typename FloatType>
|
template <typename FloatType>
|
||||||
char* to_chars(char* first, char* last, FloatType value)
|
char* to_chars(char* first, char* last, FloatType value)
|
||||||
{
|
{
|
||||||
|
@ -8564,8 +8630,8 @@ class serializer
|
||||||
}
|
}
|
||||||
|
|
||||||
// If number_float_t is an IEEE-754 single or double precision number,
|
// If number_float_t is an IEEE-754 single or double precision number,
|
||||||
// use the Grisu2 algorithm to produce short numbers which are guaranteed
|
// use the Grisu2 algorithm to produce short numbers which are
|
||||||
// to round-trip, using strtof and strtod, resp.
|
// guaranteed to round-trip, using strtof and strtod, resp.
|
||||||
//
|
//
|
||||||
// NB: The test below works if <long double> == <double>.
|
// NB: The test below works if <long double> == <double>.
|
||||||
static constexpr bool is_ieee_single_or_double
|
static constexpr bool is_ieee_single_or_double
|
||||||
|
|
|
@ -60,26 +60,28 @@ static float make_float(uint64_t f, int e)
|
||||||
constexpr int kDenormalExponent = 1 - kExponentBias;
|
constexpr int kDenormalExponent = 1 - kExponentBias;
|
||||||
constexpr int kMaxExponent = 0xFF - kExponentBias;
|
constexpr int kMaxExponent = 0xFF - kExponentBias;
|
||||||
|
|
||||||
while (f > kHiddenBit + kSignificandMask) {
|
while (f > kHiddenBit + kSignificandMask)
|
||||||
|
{
|
||||||
f >>= 1;
|
f >>= 1;
|
||||||
e++;
|
e++;
|
||||||
}
|
}
|
||||||
if (e >= kMaxExponent) {
|
if (e >= kMaxExponent)
|
||||||
|
{
|
||||||
return std::numeric_limits<float>::infinity();
|
return std::numeric_limits<float>::infinity();
|
||||||
}
|
}
|
||||||
if (e < kDenormalExponent) {
|
if (e < kDenormalExponent)
|
||||||
|
{
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
while (e > kDenormalExponent && (f & kHiddenBit) == 0) {
|
while (e > kDenormalExponent && (f & kHiddenBit) == 0)
|
||||||
|
{
|
||||||
f <<= 1;
|
f <<= 1;
|
||||||
e--;
|
e--;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t biased_exponent;
|
uint64_t biased_exponent = (e == kDenormalExponent && (f & kHiddenBit) == 0)
|
||||||
if (e == kDenormalExponent && (f & kHiddenBit) == 0)
|
? 0
|
||||||
biased_exponent = 0;
|
: static_cast<uint64_t>(e + kExponentBias);
|
||||||
else
|
|
||||||
biased_exponent = static_cast<uint64_t>(e + kExponentBias);
|
|
||||||
|
|
||||||
uint64_t bits = (f & kSignificandMask) | (biased_exponent << kPhysicalSignificandSize);
|
uint64_t bits = (f & kSignificandMask) | (biased_exponent << kPhysicalSignificandSize);
|
||||||
return reinterpret_bits<float>(static_cast<uint32_t>(bits));
|
return reinterpret_bits<float>(static_cast<uint32_t>(bits));
|
||||||
|
@ -110,26 +112,28 @@ static double make_double(uint64_t f, int e)
|
||||||
constexpr int kDenormalExponent = 1 - kExponentBias;
|
constexpr int kDenormalExponent = 1 - kExponentBias;
|
||||||
constexpr int kMaxExponent = 0x7FF - kExponentBias;
|
constexpr int kMaxExponent = 0x7FF - kExponentBias;
|
||||||
|
|
||||||
while (f > kHiddenBit + kSignificandMask) {
|
while (f > kHiddenBit + kSignificandMask)
|
||||||
|
{
|
||||||
f >>= 1;
|
f >>= 1;
|
||||||
e++;
|
e++;
|
||||||
}
|
}
|
||||||
if (e >= kMaxExponent) {
|
if (e >= kMaxExponent)
|
||||||
|
{
|
||||||
return std::numeric_limits<double>::infinity();
|
return std::numeric_limits<double>::infinity();
|
||||||
}
|
}
|
||||||
if (e < kDenormalExponent) {
|
if (e < kDenormalExponent)
|
||||||
|
{
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
while (e > kDenormalExponent && (f & kHiddenBit) == 0) {
|
while (e > kDenormalExponent && (f & kHiddenBit) == 0)
|
||||||
|
{
|
||||||
f <<= 1;
|
f <<= 1;
|
||||||
e--;
|
e--;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t biased_exponent;
|
uint64_t biased_exponent = (e == kDenormalExponent && (f & kHiddenBit) == 0)
|
||||||
if (e == kDenormalExponent && (f & kHiddenBit) == 0)
|
? 0
|
||||||
biased_exponent = 0;
|
: static_cast<uint64_t>(e + kExponentBias);
|
||||||
else
|
|
||||||
biased_exponent = static_cast<uint64_t>(e + kExponentBias);
|
|
||||||
|
|
||||||
uint64_t bits = (f & kSignificandMask) | (biased_exponent << kPhysicalSignificandSize);
|
uint64_t bits = (f & kSignificandMask) | (biased_exponent << kPhysicalSignificandSize);
|
||||||
return reinterpret_bits<double>(bits);
|
return reinterpret_bits<double>(bits);
|
||||||
|
@ -139,7 +143,7 @@ TEST_CASE("digit gen")
|
||||||
{
|
{
|
||||||
SECTION("single precision")
|
SECTION("single precision")
|
||||||
{
|
{
|
||||||
auto check_float = [](float number, const std::string& digits, int expected_exponent)
|
auto check_float = [](float number, const std::string & digits, int expected_exponent)
|
||||||
{
|
{
|
||||||
CAPTURE(number);
|
CAPTURE(number);
|
||||||
CAPTURE(digits);
|
CAPTURE(digits);
|
||||||
|
@ -203,7 +207,7 @@ TEST_CASE("digit gen")
|
||||||
|
|
||||||
SECTION("double precision")
|
SECTION("double precision")
|
||||||
{
|
{
|
||||||
auto check_double = [](double number, const std::string& digits, int expected_exponent)
|
auto check_double = [](double number, const std::string & digits, int expected_exponent)
|
||||||
{
|
{
|
||||||
CAPTURE(number);
|
CAPTURE(number);
|
||||||
CAPTURE(digits);
|
CAPTURE(digits);
|
||||||
|
@ -349,7 +353,7 @@ TEST_CASE("formatting")
|
||||||
{
|
{
|
||||||
SECTION("single precision")
|
SECTION("single precision")
|
||||||
{
|
{
|
||||||
auto check_float = [](float number, const std::string& expected)
|
auto check_float = [](float number, const std::string & expected)
|
||||||
{
|
{
|
||||||
char buf[32];
|
char buf[32];
|
||||||
char* end = nlohmann::detail::to_chars(buf, buf + 32, number);
|
char* end = nlohmann::detail::to_chars(buf, buf + 32, number);
|
||||||
|
@ -409,7 +413,7 @@ TEST_CASE("formatting")
|
||||||
|
|
||||||
SECTION("double precision")
|
SECTION("double precision")
|
||||||
{
|
{
|
||||||
auto check_double = [](double number, const std::string& expected)
|
auto check_double = [](double number, const std::string & expected)
|
||||||
{
|
{
|
||||||
char buf[32];
|
char buf[32];
|
||||||
char* end = nlohmann::detail::to_chars(buf, buf + 32, number);
|
char* end = nlohmann::detail::to_chars(buf, buf + 32, number);
|
||||||
|
|
Loading…
Reference in a new issue