Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yaml-cpp
Overview
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
lvzhengyang
yaml-cpp
Commits
f4bca79d
Commit
f4bca79d
authored
Jul 16, 2024
by
Simon Gene Gottlieb
Committed by
Jesse Beder
Nov 07, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: fp_to_string uses now 2 spaces
parent
d4e00bd4
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
146 additions
and
146 deletions
+146
-146
include/yaml-cpp/fp_to_string.h
+140
-140
test/fp_to_string_test.cpp
+6
-6
No files found.
include/yaml-cpp/fp_to_string.h
View file @
f4bca79d
...
...
@@ -20,9 +20,9 @@ namespace fp_formatting {
* Converts a integer into its ASCII digits.
*
* @param begin/end - a buffer, must be at least 20bytes long
* @param value
- input value
* @param width
- minimum number of digits, fill with '0' to the left. Must be equal or smaller than the buffer size.
* @return
- number of digits filled into the buffer.
* @param value - input value
* @param width - minimum number of digits, fill with '0' to the left. Must be equal or smaller than the buffer size.
* @return - number of digits filled into the buffer.
*
* Example:
* std::array<char, 20> buffer;
...
...
@@ -33,27 +33,27 @@ namespace fp_formatting {
* assert(buffer[2] == '3');
*/
inline
auto
ConvertToChars
(
char
*
begin
,
char
*
end
,
size_t
value
,
int
width
=
1
)
->
int
{
assert
(
width
>=
1
);
assert
(
end
>=
begin
);
// end must be after begin
assert
(
end
-
begin
>=
width
);
// Buffer must be large enough
assert
(
end
-
begin
>=
20
);
// 2^64 has 20digits, so at least 20 digits must be available
// count number of digits, and fill digits array accordingly
int
digits_ct
{};
while
(
value
>
0
)
{
char
c
=
value
%
10
+
'0'
;
value
=
value
/
10
;
digits_ct
+=
1
;
*
(
end
-
digits_ct
)
=
c
;
}
while
(
digits_ct
<
width
)
{
assert
(
digits_ct
<
64
);
digits_ct
+=
1
;
*
(
end
-
digits_ct
)
=
'0'
;
}
// move data to the front of the array
std
::
memmove
(
begin
,
end
-
digits_ct
,
digits_ct
);
return
digits_ct
;
assert
(
width
>=
1
);
assert
(
end
>=
begin
);
// end must be after begin
assert
(
end
-
begin
>=
width
);
// Buffer must be large enough
assert
(
end
-
begin
>=
20
);
// 2^64 has 20digits, so at least 20 digits must be available
// count number of digits, and fill digits array accordingly
int
digits_ct
{};
while
(
value
>
0
)
{
char
c
=
value
%
10
+
'0'
;
value
=
value
/
10
;
digits_ct
+=
1
;
*
(
end
-
digits_ct
)
=
c
;
}
while
(
digits_ct
<
width
)
{
assert
(
digits_ct
<
64
);
digits_ct
+=
1
;
*
(
end
-
digits_ct
)
=
'0'
;
}
// move data to the front of the array
std
::
memmove
(
begin
,
end
-
digits_ct
,
digits_ct
);
return
digits_ct
;
}
/**
...
...
@@ -63,144 +63,144 @@ inline auto ConvertToChars(char* begin, char* end, size_t value, int width=1) ->
*/
template
<
typename
T
>
auto
FpToString
(
T
v
,
int
precision
=
0
)
->
std
::
string
{
// assert(precision > 0);
// hardcoded constant, at which exponent should switch to a scientific notation
int
const
lowerExponentThreshold
=
-
5
;
int
const
upperExponentThreshold
=
(
precision
==
0
)
?
6
:
precision
;
if
(
precision
==
0
)
{
precision
=
6
;
}
// dragonbox/to_decimal does not handle value 0, inf, NaN
if
(
v
==
0
||
std
::
isinf
(
v
)
||
std
::
isnan
(
v
))
{
std
::
stringstream
ss
;
ss
<<
v
;
return
ss
.
str
();
}
auto
r
=
jkj
::
dragonbox
::
to_decimal
(
v
);
auto
digits
=
std
::
array
<
char
,
20
>
{};
// max digits of size_t is 20.
auto
digits_ct
=
ConvertToChars
(
digits
.
data
(),
digits
.
data
()
+
digits
.
size
(),
r
.
significand
);
// check if requested precision is lower than
// required digits for exact representation
if
(
digits_ct
>
precision
)
{
auto
diff
=
digits_ct
-
precision
;
r
.
exponent
+=
diff
;
digits_ct
=
precision
;
// round numbers if required
if
(
digits
[
digits_ct
]
>=
'5'
)
{
int
i
{
digits_ct
-
1
};
digits
[
i
]
+=
1
;
while
(
digits
[
i
]
==
'9'
+
1
)
{
digits_ct
-=
1
;
r
.
exponent
+=
1
;
if
(
i
>
0
)
{
digits
[
i
-
1
]
+=
1
;
i
-=
1
;
}
else
{
digits_ct
=
1
;
digits
[
0
]
=
'1'
;
break
;
}
}
// assert(precision > 0);
// hardcoded constant, at which exponent should switch to a scientific notation
int
const
lowerExponentThreshold
=
-
5
;
int
const
upperExponentThreshold
=
(
precision
==
0
)
?
6
:
precision
;
if
(
precision
==
0
)
{
precision
=
6
;
}
// dragonbox/to_decimal does not handle value 0, inf, NaN
if
(
v
==
0
||
std
::
isinf
(
v
)
||
std
::
isnan
(
v
))
{
std
::
stringstream
ss
;
ss
<<
v
;
return
ss
.
str
();
}
auto
r
=
jkj
::
dragonbox
::
to_decimal
(
v
);
auto
digits
=
std
::
array
<
char
,
20
>
{};
// max digits of size_t is 20.
auto
digits_ct
=
ConvertToChars
(
digits
.
data
(),
digits
.
data
()
+
digits
.
size
(),
r
.
significand
);
// check if requested precision is lower than
// required digits for exact representation
if
(
digits_ct
>
precision
)
{
auto
diff
=
digits_ct
-
precision
;
r
.
exponent
+=
diff
;
digits_ct
=
precision
;
// round numbers if required
if
(
digits
[
digits_ct
]
>=
'5'
)
{
int
i
{
digits_ct
-
1
};
digits
[
i
]
+=
1
;
while
(
digits
[
i
]
==
'9'
+
1
)
{
digits_ct
-=
1
;
r
.
exponent
+=
1
;
if
(
i
>
0
)
{
digits
[
i
-
1
]
+=
1
;
i
-=
1
;
}
else
{
digits_ct
=
1
;
digits
[
0
]
=
'1'
;
break
;
}
}
}
std
::
array
<
char
,
28
>
output_buffer
;
// max digits of size_t plus sign, a dot and 2 letters for 'e+' or 'e-' and 4 letters for the exponent
auto
output_ptr
=
&
output_buffer
[
0
];
// print '-' symbol for negative numbers
if
(
r
.
is_negative
)
{
*
(
output_ptr
++
)
=
'-'
;
}
std
::
array
<
char
,
28
>
output_buffer
;
// max digits of size_t plus sign, a dot and 2 letters for 'e+' or 'e-' and 4 letters for the exponent
auto
output_ptr
=
&
output_buffer
[
0
];
// print '-' symbol for negative numbers
if
(
r
.
is_negative
)
{
*
(
output_ptr
++
)
=
'-'
;
}
// exponent if only a single non-zero digit is before the decimal point
int
const
exponent
=
r
.
exponent
+
digits_ct
-
1
;
// case 1: scientific notation
if
(
exponent
>=
upperExponentThreshold
||
exponent
<=
lowerExponentThreshold
)
{
// print first digit
*
(
output_ptr
++
)
=
digits
[
0
];
// print digits after decimal point
if
(
digits_ct
>
1
)
{
*
(
output_ptr
++
)
=
'.'
;
// print significant numbers after decimal point
for
(
int
i
{
1
};
i
<
digits_ct
;
++
i
)
{
*
(
output_ptr
++
)
=
digits
[
i
];
}
}
*
(
output_ptr
++
)
=
'e'
;
*
(
output_ptr
++
)
=
(
exponent
>=
0
)
?
'+'
:
'-'
;
auto
exp_digits
=
std
::
array
<
char
,
20
>
{};
auto
exp_digits_ct
=
ConvertToChars
(
exp_digits
.
data
(),
exp_digits
.
data
()
+
exp_digits
.
size
(),
std
::
abs
(
exponent
),
/*.precision=*/
2
);
for
(
int
i
{
0
};
i
<
exp_digits_ct
;
++
i
)
{
*
(
output_ptr
++
)
=
exp_digits
[
i
];
}
// exponent if only a single non-zero digit is before the decimal point
int
const
exponent
=
r
.
exponent
+
digits_ct
-
1
;
// case 1: scientific notation
if
(
exponent
>=
upperExponentThreshold
||
exponent
<=
lowerExponentThreshold
)
{
// print first digit
*
(
output_ptr
++
)
=
digits
[
0
];
// print digits after decimal point
if
(
digits_ct
>
1
)
{
*
(
output_ptr
++
)
=
'.'
;
// print significant numbers after decimal point
for
(
int
i
{
1
};
i
<
digits_ct
;
++
i
)
{
*
(
output_ptr
++
)
=
digits
[
i
];
}
}
*
(
output_ptr
++
)
=
'e'
;
*
(
output_ptr
++
)
=
(
exponent
>=
0
)
?
'+'
:
'-'
;
auto
exp_digits
=
std
::
array
<
char
,
20
>
{};
auto
exp_digits_ct
=
ConvertToChars
(
exp_digits
.
data
(),
exp_digits
.
data
()
+
exp_digits
.
size
(),
std
::
abs
(
exponent
),
/*.precision=*/
2
);
for
(
int
i
{
0
};
i
<
exp_digits_ct
;
++
i
)
{
*
(
output_ptr
++
)
=
exp_digits
[
i
];
}
// case 2: default notation
// case 2: default notation
}
else
{
auto
const
digits_end
=
digits
.
begin
()
+
digits_ct
;
auto
digits_iter
=
digits
.
begin
();
// print digits before point
int
const
before_decimal_digits
=
digits_ct
+
r
.
exponent
;
if
(
before_decimal_digits
>
0
)
{
// print digits before point
for
(
int
i
{
0
};
i
<
std
::
min
(
before_decimal_digits
,
digits_ct
);
++
i
)
{
*
(
output_ptr
++
)
=
*
(
digits_iter
++
);
}
// print trailing zeros before point
for
(
int
i
{
0
};
i
<
before_decimal_digits
-
digits_ct
;
++
i
)
{
*
(
output_ptr
++
)
=
'0'
;
}
// print 0 before point if none where printed before
}
else
{
auto
const
digits_end
=
digits
.
begin
()
+
digits_ct
;
auto
digits_iter
=
digits
.
begin
();
// print digits before point
int
const
before_decimal_digits
=
digits_ct
+
r
.
exponent
;
if
(
before_decimal_digits
>
0
)
{
// print digits before point
for
(
int
i
{
0
};
i
<
std
::
min
(
before_decimal_digits
,
digits_ct
);
++
i
)
{
*
(
output_ptr
++
)
=
*
(
digits_iter
++
);
}
// print trailing zeros before point
for
(
int
i
{
0
};
i
<
before_decimal_digits
-
digits_ct
;
++
i
)
{
*
(
output_ptr
++
)
=
'0'
;
}
// print 0 before point if none where printed before
}
else
{
*
(
output_ptr
++
)
=
'0'
;
}
*
(
output_ptr
++
)
=
'0'
;
}
if
(
digits_iter
!=
digits_end
)
{
*
(
output_ptr
++
)
=
'.'
;
// print 0 afer decimal point, to fill until first digits
int
const
after_decimal_zeros
=
-
digits_ct
-
r
.
exponent
;
for
(
int
i
{
0
};
i
<
after_decimal_zeros
;
++
i
)
{
*
(
output_ptr
++
)
=
'0'
;
}
// print significant numbers after decimal point
for
(;
digits_iter
<
digits_end
;
++
digits_iter
)
{
*
(
output_ptr
++
)
=
*
digits_iter
;
}
}
if
(
digits_iter
!=
digits_end
)
{
*
(
output_ptr
++
)
=
'.'
;
// print 0 afer decimal point, to fill until first digits
int
const
after_decimal_zeros
=
-
digits_ct
-
r
.
exponent
;
for
(
int
i
{
0
};
i
<
after_decimal_zeros
;
++
i
)
{
*
(
output_ptr
++
)
=
'0'
;
}
// print significant numbers after decimal point
for
(;
digits_iter
<
digits_end
;
++
digits_iter
)
{
*
(
output_ptr
++
)
=
*
digits_iter
;
}
}
*
output_ptr
=
'\0'
;
return
std
::
string
{
&
output_buffer
[
0
],
output_ptr
};
}
*
output_ptr
=
'\0'
;
return
std
::
string
{
&
output_buffer
[
0
],
output_ptr
};
}
}
}
inline
auto
FpToString
(
float
v
,
size_t
precision
=
0
)
->
std
::
string
{
return
detail
::
fp_formatting
::
FpToString
(
v
,
precision
);
return
detail
::
fp_formatting
::
FpToString
(
v
,
precision
);
}
inline
auto
FpToString
(
double
v
,
size_t
precision
=
0
)
->
std
::
string
{
return
detail
::
fp_formatting
::
FpToString
(
v
,
precision
);
return
detail
::
fp_formatting
::
FpToString
(
v
,
precision
);
}
/**
* dragonbox only works for floats/doubles not long double
*/
inline
auto
FpToString
(
long
double
v
,
size_t
precision
=
std
::
numeric_limits
<
long
double
>::
max_digits10
)
->
std
::
string
{
std
::
stringstream
ss
;
ss
.
precision
(
precision
);
ss
.
imbue
(
std
::
locale
(
"C"
)
);
ss
<<
v
;
return
ss
.
str
();
std
::
stringstream
ss
;
ss
.
imbue
(
std
::
locale
(
"C"
)
);
ss
.
precision
(
precision
);
ss
<<
v
;
return
ss
.
str
();
}
}
...
...
test/fp_to_string_test.cpp
View file @
f4bca79d
...
...
@@ -9,12 +9,12 @@ namespace {
*/
template
<
typename
T
>
static
std
::
string
convert_with_stringstream
(
T
v
,
size_t
precision
=
0
)
{
std
::
stringstream
ss
;
if
(
precision
>
0
)
{
ss
<<
std
::
setprecision
(
precision
);
}
ss
<<
v
;
return
ss
.
str
();
std
::
stringstream
ss
;
if
(
precision
>
0
)
{
ss
<<
std
::
setprecision
(
precision
);
}
ss
<<
v
;
return
ss
.
str
();
}
// Caution: Test involving 'convert_with_stringstream' are based on std::stringstream
...
...
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