Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
J
json
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
json
Commits
3cca6308
Unverified
Commit
3cca6308
authored
Jan 21, 2018
by
Niels Lohmann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
🔨
cleanup after #915
parent
010e5960
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
366 additions
and
230 deletions
+366
-230
Makefile
Makefile
+1
-0
README.md
README.md
+1
-2
to_chars.hpp
develop/detail/conversions/to_chars.hpp
+167
-101
serializer.hpp
develop/detail/serializer.hpp
+2
-2
json.hpp
src/json.hpp
+169
-103
unit-to_chars.cpp
test/src/unit-to_chars.cpp
+26
-22
No files found.
Makefile
View file @
3cca6308
...
@@ -8,6 +8,7 @@ SRCS = develop/json.hpp \
...
@@ -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
\
...
...
README.md
View file @
3cca6308
...
@@ -821,8 +821,6 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I
...
@@ -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.
...
@@ -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.
...
...
develop/detail/conversions/to_chars.hpp
View file @
3cca6308
...
@@ -11,24 +11,30 @@ namespace nlohmann
...
@@ -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
...
@@ -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)
...
@@ -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)
...
@@ -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
...
@@ -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)
...
@@ -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)
...
@@ -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
...
@@ -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)
...
@@ -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
...
@@ -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
...
@@ -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
...
@@ -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)
...
@@ -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)
...
@@ -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
...
@@ -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
)
{
{
...
...
develop/detail/serializer.hpp
View file @
3cca6308
...
@@ -483,8 +483,8 @@ class serializer
...
@@ -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
...
...
src/json.hpp
View file @
3cca6308
...
@@ -7077,24 +7077,30 @@ namespace nlohmann
...
@@ -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
...
@@ -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
static
diyfp
sub
(
diyfp
x
,
diyfp
y
);
// Returns x * y.
// 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
@brief returns x - y
static
diyfp
normalize
(
diyfp
x
);
@pre x.e == y.e and x.f >= y.f
*/
// Normalize x such that the result has the exponent E.
static
diyfp
sub
(
const
diyfp
&
x
,
const
diyfp
&
y
)
noexcept
// 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)
...
@@ -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)
...
@@ -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
...
@@ -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)
...
@@ -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)
...
@@ -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
...
@@ -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)
...
@@ -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
...
@@ -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
...
@@ -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
...
@@ -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)
...
@@ -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)
...
@@ -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
...
@@ -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
...
@@ -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
...
...
test/src/unit-to_chars.cpp
View file @
3cca6308
...
@@ -60,26 +60,28 @@ static float make_float(uint64_t f, int e)
...
@@ -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)
...
@@ -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")
...
@@ -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")
...
@@ -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")
...
@@ -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")
...
@@ -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
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment