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
2a952dd0
Commit
2a952dd0
authored
6 years ago
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement some formatting options in Grisu
parent
0de44a46
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
74 additions
and
20 deletions
+74
-20
include/fmt/format-inl.h
include/fmt/format-inl.h
+67
-14
include/fmt/format.h
include/fmt/format.h
+7
-6
No files found.
include/fmt/format-inl.h
View file @
2a952dd0
...
...
@@ -364,12 +364,14 @@ FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
return
fp
(
data
::
POW10_SIGNIFICANDS
[
index
],
data
::
POW10_EXPONENTS
[
index
]);
}
// Writes the exponent exp in the form "[-]d{1,3}" to buffer.
// Writes the exponent exp in the form "[
+
-]d{1,3}" to buffer.
FMT_FUNC
char
*
write_exponent
(
char
*
buffer
,
int
exp
)
{
FMT_ASSERT
(
-
1000
<
exp
&&
exp
<
1000
,
"exponent out of range"
);
if
(
exp
<
0
)
{
*
buffer
++
=
'-'
;
exp
=
-
exp
;
}
else
{
*
buffer
++
=
'+'
;
}
if
(
exp
>=
100
)
{
*
buffer
++
=
'0'
+
static_cast
<
char
>
(
exp
/
100
);
...
...
@@ -446,25 +448,56 @@ FMT_FUNC void grisu2_gen_digits(
// Prettifies the output of the Grisu2 algorithm.
// The number is given as v = buffer * 10^exp.
FMT_FUNC
void
grisu2_prettify
(
char
*
buffer
,
size_t
&
size
,
int
exp
)
{
FMT_FUNC
void
grisu2_prettify
(
char
*
buffer
,
size_t
&
size
,
int
exp
,
char
type
,
int
precision
,
bool
print_decimal_point
)
{
int
int_size
=
static_cast
<
int
>
(
size
);
// 10^(full_exp - 1) <= v <= 10^full_exp.
int
full_exp
=
static_cast
<
int
>
(
size
)
+
exp
;
// Insert a decimal point after the first digit and add an exponent.
std
::
memmove
(
buffer
+
2
,
buffer
+
1
,
size
-
1
);
buffer
[
1
]
=
'.'
;
char
*
p
=
buffer
+
size
+
1
;
*
p
++
=
'e'
;
size
=
to_unsigned
(
write_exponent
(
p
,
full_exp
-
1
)
-
buffer
);
int
full_exp
=
int_size
+
exp
;
if
(
int_size
<=
full_exp
&&
full_exp
<=
21
)
{
// 1234e7 -> 12340000000
char
*
p
=
std
::
uninitialized_fill_n
(
buffer
+
int_size
,
full_exp
-
int_size
,
'0'
);
if
(
print_decimal_point
&&
int_size
<
precision
)
{
*
p
++
=
'.'
;
p
=
std
::
uninitialized_fill_n
(
p
,
precision
-
int_size
,
'0'
);
}
size
=
to_unsigned
(
p
-
buffer
);
}
else
if
(
0
<
full_exp
&&
full_exp
<=
21
)
{
// 1234e-2 -> 12.34
size_t
fractional_size
=
int_size
-
full_exp
;
std
::
memmove
(
buffer
+
full_exp
+
1
,
buffer
+
full_exp
,
fractional_size
);
buffer
[
full_exp
]
=
'.'
;
if
(
type
==
'f'
&&
fractional_size
<
precision
)
{
size_t
num_zeros
=
precision
-
fractional_size
;
std
::
uninitialized_fill_n
(
buffer
+
size
+
1
,
num_zeros
,
'0'
);
size
+=
num_zeros
;
}
++
size
;
}
else
if
(
-
6
<
full_exp
&&
full_exp
<=
0
)
{
// 1234e-6 -> 0.001234
int
offset
=
2
-
full_exp
;
std
::
memmove
(
buffer
+
offset
,
buffer
,
size
);
buffer
[
0
]
=
'0'
;
buffer
[
1
]
=
'.'
;
std
::
uninitialized_fill_n
(
buffer
+
2
,
-
full_exp
,
'0'
);
size
=
to_unsigned
(
int_size
+
offset
);
}
else
{
// Insert a decimal point after the first digit and add an exponent.
std
::
memmove
(
buffer
+
2
,
buffer
+
1
,
size
-
1
);
buffer
[
1
]
=
'.'
;
char
*
p
=
buffer
+
size
+
1
;
*
p
++
=
'e'
;
size
=
to_unsigned
(
write_exponent
(
p
,
full_exp
-
1
)
-
buffer
);
}
}
// Formats value using Grisu2 algorithm. Grisu2 doesn't give any guarantees on
// the shortness of the result.
FMT_FUNC
void
grisu2_format
(
double
value
,
char
*
buffer
,
size_t
&
size
)
{
FMT_FUNC
void
grisu2_format_positive
(
double
value
,
char
*
buffer
,
size_t
&
size
,
int
&
dec_exp
)
{
FMT_ASSERT
(
value
>
0
,
"value is nonpositive"
);
fp
fp_value
(
value
);
fp
lower
,
upper
;
// w^- and w^+ in the Grisu paper.
fp_value
.
compute_boundaries
(
lower
,
upper
);
// Find a cached power of 10 close to 1 / upper.
int
dec_exp
=
0
;
// K in Grisu.
const
int
min_exp
=
-
60
;
// alpha in Grisu.
auto
dec_pow
=
get_cached_power
(
// \tilde{c}_{-k} in Grisu.
min_exp
-
(
upper
.
e
+
fp
::
significand_size
),
dec_exp
);
...
...
@@ -477,7 +510,27 @@ FMT_FUNC void grisu2_format(double value, char *buffer, size_t &size) {
--
scaled_upper
.
f
;
// \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
uint64_t
delta
=
scaled_upper
.
f
-
scaled_lower
.
f
;
grisu2_gen_digits
(
scaled_value
,
scaled_upper
,
delta
,
buffer
,
size
,
dec_exp
);
grisu2_prettify
(
buffer
,
size
,
dec_exp
);
}
// Formats value using Grisu2 algorithm. Grisu2 doesn't give any guarantees on
// the shortness of the result.
FMT_FUNC
void
grisu2_format
(
double
value
,
char
*
buffer
,
size_t
&
size
,
char
type
,
int
precision
,
bool
print_decimal_point
)
{
int
dec_exp
=
0
;
// K in Grisu.
if
(
value
!=
0
)
{
grisu2_format_positive
(
value
,
buffer
,
size
,
dec_exp
);
}
else
{
*
buffer
=
'0'
;
size
=
1
;
}
if
(
precision
<
0
)
precision
=
6
;
if
(
size
>
precision
)
{
// TODO: round instead of truncating
dec_exp
+=
size
-
precision
;
size
=
precision
;
}
grisu2_prettify
(
buffer
,
size
,
dec_exp
,
type
,
precision
,
print_decimal_point
);
}
}
// namespace internal
...
...
This diff is collapsed.
Click to expand it.
include/fmt/format.h
View file @
2a952dd0
...
...
@@ -367,7 +367,8 @@ FMT_API fp get_cached_power(int min_exponent, int &pow10_exponent);
// Formats value using Grisu2 algorithm:
// https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf
FMT_API void grisu2_format(double value, char *buffer, size_t &size);
FMT_API void grisu2_format(double value, char *buffer, size_t &size, char type,
int precision, bool print_decimal_point);
template <typename Allocator>
typename Allocator::value_type *allocate(Allocator& alloc, std::size_t n) {
...
...
@@ -2949,12 +2950,12 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
basic_memory_buffer<char_type> buffer;
if (internal::const_check(FMT_USE_GRISU && sizeof(T) <= sizeof(double) &&
std::numeric_limits<double>::is_iec559)) {
// The max size = 10 (hi) + 20 (lo) + 5 (exp).
enum { BUF_SIZE = 35 };
char buf[BUF_SIZE];
char buf[100]; // TODO: correct buffer size
size_t size = 0;
internal::grisu2_format(static_cast<double>(value), buf, size);
FMT_ASSERT(size <= BUF_SIZE, "buffer overflow");
internal::grisu2_format(
static_cast<double>(value), buf, size, static_cast<char>(spec.type()),
spec.precision(), spec.flag(HASH_FLAG));
FMT_ASSERT(size <= 100, "buffer overflow");
buffer.append(buf, buf + size); // TODO: avoid extra copy
} else {
format_specs normalized_spec(spec);
...
...
This diff is collapsed.
Click to expand it.
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