Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
F
fmt
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
fmt
Commits
ac71d853
Commit
ac71d853
authored
Sep 07, 2019
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor normalize and clean up
parent
6649b8e0
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
31 additions
and
30 deletions
+31
-30
include/fmt/core.h
include/fmt/core.h
+1
-1
include/fmt/format-inl.h
include/fmt/format-inl.h
+26
-25
test/format-impl-test.cc
test/format-impl-test.cc
+4
-4
No files found.
include/fmt/core.h
View file @
ac71d853
...
...
@@ -245,7 +245,7 @@ struct int128_t {};
struct
uint128_t
{};
#endif
// Casts nonnegative integer to unsigned.
// Casts
a
nonnegative integer to unsigned.
template
<
typename
Int
>
FMT_CONSTEXPR
typename
std
::
make_unsigned
<
Int
>::
type
to_unsigned
(
Int
value
)
{
FMT_ASSERT
(
value
>=
0
,
"negative value"
);
...
...
include/fmt/format-inl.h
View file @
ac71d853
...
...
@@ -49,9 +49,6 @@
# pragma warning(push)
# pragma warning(disable : 4127) // conditional expression is constant
# pragma warning(disable : 4702) // unreachable code
// Disable deprecation warning for strerror. The latter is not called but
// MSVC fails to detect it.
# pragma warning(disable : 4996)
#endif
// Dummy implementations of strerror_r and strerror_s called if corresponding
...
...
@@ -81,7 +78,7 @@ inline int fmt_snprintf(char* buffer, size_t size, const char* format, ...) {
using
format_func
=
void
(
*
)(
internal
::
buffer
<
char
>&
,
int
,
string_view
);
//
P
ortable thread-safe version of strerror.
//
A p
ortable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code.
// This can be either a pointer to a string stored in buffer,
// or a pointer to some static immutable string.
...
...
@@ -352,6 +349,9 @@ template <typename T> struct bits {
static_cast
<
int
>
(
sizeof
(
T
)
*
std
::
numeric_limits
<
unsigned
char
>::
digits
);
};
class
fp
;
template
<
int
SHIFT
=
0
>
fp
normalize
(
fp
value
);
// A handmade floating-point number f * pow(2, e).
class
fp
{
private:
...
...
@@ -396,28 +396,29 @@ class fp {
}
// Normalizes the value converted from double and multiplied by (1 << SHIFT).
template
<
int
SHIFT
=
0
>
void
normalize
(
)
{
template
<
int
SHIFT
>
friend
fp
normalize
(
fp
value
)
{
// Handle subnormals.
auto
shifted_implicit_bit
=
implicit_bit
<<
SHIFT
;
while
((
f
&
shifted_implicit_bit
)
==
0
)
{
f
<<=
1
;
--
e
;
const
auto
shifted_implicit_bit
=
implicit_bit
<<
SHIFT
;
while
((
value
.
f
&
shifted_implicit_bit
)
==
0
)
{
value
.
f
<<=
1
;
--
value
.
e
;
}
// Subtract 1 to account for hidden bit.
auto
offset
=
significand_size
-
double_significand_size
-
SHIFT
-
1
;
f
<<=
offset
;
e
-=
offset
;
const
auto
offset
=
significand_size
-
double_significand_size
-
SHIFT
-
1
;
value
.
f
<<=
offset
;
value
.
e
-=
offset
;
return
value
;
}
// Compute lower and upper boundaries (m^- and m^+ in the Grisu paper), where
// Compute
s
lower and upper boundaries (m^- and m^+ in the Grisu paper), where
// a boundary is a value half way between the number and its predecessor
// (lower) or successor (upper). The upper boundary is normalized and lower
// has the same exponent but may be not normalized.
void
compute_boundaries
(
fp
&
lower
,
fp
&
upper
)
const
{
lower
=
f
==
implicit_bit
?
fp
((
f
<<
2
)
-
1
,
e
-
2
)
:
fp
((
f
<<
1
)
-
1
,
e
-
1
);
upper
=
fp
((
f
<<
1
)
+
1
,
e
-
1
);
upper
.
normalize
<
1
>
();
// 1 is to account for the exponent shift above.
// 1 in normalize accounts for the exponent shift above.
upper
=
normalize
<
1
>
(
fp
((
f
<<
1
)
+
1
,
e
-
1
));
lower
.
f
<<=
lower
.
e
-
upper
.
e
;
lower
.
e
=
upper
.
e
;
}
...
...
@@ -716,7 +717,7 @@ template <typename Double,
FMT_API
bool
grisu_format
(
Double
value
,
buffer
<
char
>&
buf
,
int
precision
,
unsigned
options
,
int
&
exp
)
{
FMT_ASSERT
(
value
>=
0
,
"value is negative"
);
bool
fixed
=
(
options
&
grisu_options
::
fixed
)
!=
0
;
const
bool
fixed
=
(
options
&
grisu_options
::
fixed
)
!=
0
;
if
(
value
<=
0
)
{
// <= instead of == to silence a warning.
if
(
precision
<=
0
||
!
fixed
)
{
exp
=
0
;
...
...
@@ -729,17 +730,17 @@ FMT_API bool grisu_format(Double value, buffer<char>& buf, int precision,
return
true
;
}
fp
fp_value
(
value
);
const
fp
fp_value
(
value
);
const
int
min_exp
=
-
60
;
// alpha in Grisu.
int
cached_exp10
=
0
;
// K in Grisu.
if
(
precision
!=
-
1
)
{
if
(
precision
>
17
)
return
false
;
fp
_value
.
normalize
(
);
fp
normalized
=
normalize
(
fp_value
);
const
auto
cached_pow
=
get_cached_power
(
min_exp
-
(
fp_value
.
e
+
fp
::
significand_size
),
cached_exp10
);
fp_value
=
fp_value
*
cached_pow
;
min_exp
-
(
normalized
.
e
+
fp
::
significand_size
),
cached_exp10
);
normalized
=
normalized
*
cached_pow
;
fixed_handler
handler
{
buf
.
data
(),
0
,
precision
,
-
cached_exp10
,
fixed
};
if
(
grisu_gen_digits
(
fp_value
,
1
,
exp
,
handler
)
==
digits
::
error
)
if
(
grisu_gen_digits
(
normalized
,
1
,
exp
,
handler
)
==
digits
::
error
)
return
false
;
buf
.
resize
(
to_unsigned
(
handler
.
size
));
}
else
{
...
...
@@ -747,10 +748,10 @@ FMT_API bool grisu_format(Double value, buffer<char>& buf, int precision,
fp_value
.
compute_boundaries
(
lower
,
upper
);
// Find a cached power of 10 such that multiplying upper by it will bring
// the exponent in the range [min_exp, -32].
auto
cached_pow
=
get_cached_power
(
// \tilde{c}_{-k} in Grisu.
const
auto
cached_pow
=
get_cached_power
(
// \tilde{c}_{-k} in Grisu.
min_exp
-
(
upper
.
e
+
fp
::
significand_size
),
cached_exp10
);
fp
_value
.
normalize
(
);
fp_value
=
fp_value
*
cached_pow
;
fp
normalized
=
normalize
(
fp_value
);
normalized
=
normalized
*
cached_pow
;
lower
=
lower
*
cached_pow
;
// \tilde{M}^- in Grisu.
upper
=
upper
*
cached_pow
;
// \tilde{M}^+ in Grisu.
assert
(
min_exp
<=
upper
.
e
&&
upper
.
e
<=
-
32
);
...
...
@@ -760,7 +761,7 @@ FMT_API bool grisu_format(Double value, buffer<char>& buf, int precision,
--
lower
.
f
;
// \tilde{M}^- - 1 ulp -> M^-_{\downarrow}.
++
upper
.
f
;
// \tilde{M}^+ + 1 ulp -> M^+_{\uparrow}.
// Numbers outside of (lower, upper) definitely do not round to value.
grisu_shortest_handler
<
3
>
handler
{
buf
.
data
(),
0
,
(
upper
-
fp_value
).
f
};
grisu_shortest_handler
<
3
>
handler
{
buf
.
data
(),
0
,
(
upper
-
normalized
).
f
};
result
=
grisu_gen_digits
(
upper
,
upper
.
f
-
lower
.
f
,
exp
,
handler
);
size
=
handler
.
size
;
if
(
result
==
digits
::
error
)
{
...
...
test/format-impl-test.cc
View file @
ac71d853
...
...
@@ -48,10 +48,10 @@ TEST(FPTest, ConstructFromDouble) {
}
TEST
(
FPTest
,
Normalize
)
{
auto
v
=
fp
(
0xbeef
,
42
);
v
.
normalize
(
);
EXPECT_EQ
(
0xbeef000000000000
,
v
.
f
);
EXPECT_EQ
(
-
6
,
v
.
e
);
const
auto
v
=
fp
(
0xbeef
,
42
);
auto
normalized
=
normalize
(
v
);
EXPECT_EQ
(
0xbeef000000000000
,
normalized
.
f
);
EXPECT_EQ
(
-
6
,
normalized
.
e
);
}
TEST
(
FPTest
,
ComputeBoundariesSubnormal
)
{
...
...
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