Code Monkey home page Code Monkey logo

charconv's People

Contributors

akrzemi1 avatar grisumbras avatar jk-jeon avatar mborland avatar pdimov avatar vinniefalco avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

charconv's Issues

Double precision from_chars parsing incorrectly on reused buffer

Examples from the benchmark PR (test_boost_to_chars with chars_format::general):

Roundtrip failure with: -1042963531082612
          to_chars val: -1042963531082612.5
          to_chars ptr: 19
        from_chars val: -1.042963531082612e+164
        from_chars ptr: 24
Roundtrip failure with: -2984127144195026
          to_chars val: -2984127144195026.5
          to_chars ptr: 19
        from_chars val: -2.984127144195027e-233
        from_chars ptr: 24
Roundtrip failure with: 1816265025891540
          to_chars val: 1816265025891539.5
          to_chars ptr: 18
        from_chars val: 1.81626502589154e-98
        from_chars ptr: 24
Roundtrip failure with: 217945471321669.8
          to_chars val: 217945471321669.75
          to_chars ptr: 18
        from_chars val: 0
        from_chars ptr: 24

Single precision does not have any issues.

result's ptr is not correct for some numbers

This fails:

string_view s = "0e0";
auto err = detail::charconv::from_chars( s.begin(), s.end(), d );
BOOST_ASSERT( err.ptr == s.end() );

Same for e.g. 0e00000000000 and 0e1.

CMake targets don't link to quadmath

I'm encountering build errors because of undefined symbols when using CMake. It looks like Boost::charconv is failing to state the dependency.

  • It occurs only when using the floating-point conversion functions.
  • It happens when consuming the library from another library, via the superproject (I found this by having my MySQL test executables link to charconv). It also happens when creating a Boost distribution using CMake, and then consuming it via find_package. It doesn't happen when consuming the Boost CMake modules generated by b2.
  • I'm seeing the errors under Ubuntu 22.04 and gcc-11. It happens under both Debug and Release, and with C++11 and C++20.
  • Adding a target_link_libraries(... quadmath) such that -lquadmath is added to the link command line fixes the issue.

Full repro:

cd $BOOST_ROOT
mkdir -p __build && cd __build
cmake -DBOOST_INCLUDE_LIBRARIES=charconv -DCMAKE_INSTALL_PREFIX=/tmp/repro/    ..
make -j8 install
cd ~/repro-consumer
mkdir __build && cd __build
cmake -DCMAKE_PREFIX_PATH=/tmp/repro/ ..
make

File ~/repro-consumer/main.cpp:

#include <boost/charconv/from_chars.hpp>

int main() {
  auto str = "42.0";
  float val = 0;
  boost::charconv::from_chars(str, str + 2, val);
}

File ~/repro-consumer/CMakeLists.txt:

cmake_minimum_required(VERSION 3.12.0)
project(boost_mysql_example LANGUAGES CXX)

find_package(Boost REQUIRED COMPONENTS charconv)

add_executable(main main.cpp)
target_link_libraries(main PRIVATE Boost::charconv)

buffer overflows in to_chars

Hello Matt,
here is a somewhat clearer test case.
test.cpp.txt

FP128
No buffer overflow, but the values in to_chars_result do not match the default.

all others
buffer overflows + wrong to_chars_result

thx
Gero

Docs: improve section "from_chars overview"

Section https://master.charconv.cpp.al/#build_from_chars is uncomfortable to read for a couple of resons.

The description of from_chars_result is wrong. ptr is just a pointer. It doesn't point to the first invalid character, or to last: there is no last in the scope of from_chars_result. ptr points to whatever the user wants it to point to. Now that you have defined this class, users can create its objects for whatever purpose they want. It is only funcitons from_chars that choose to use it in a specific way.

Please use computer font for referring to variable names. Sentene like "points to the first character not matching the pattern, or has the value of last if all characters are successfully parsed" is confusing. Words "first" and "last" seem like a pair of similar things, but in your sentence only one of them represents an object (which is not in scope).

Same for ec: the user can assign any value they want. "Valid values for are" belongs to the description of from_chars funcitons.

The description of comparisons brings no value, and is imprecise. Why not just declare:

friend constexpr bool operator==(const from_chars_result& lhs, const from_chars_result& rhs) noexcept = default;

even though it is a c++11 library?

If you insist on having the two declarations, do change their description to:

  • operator== - returns lhs.ptr == phs.ptr && lhs.ec == rhs.ec,
  • operator! - returns !(lhs == rhs).

I think that the initial section would be better off with some verbal description rather than class/function synopses. It should start from explaining that the convention of this library is to report failures via class from_chars_result with these two fields that are *intended` to represent the following situations.

buffer overflows in to_chars for std::bfloat16_t

Hi Matt,
if the buffer is too small and value = ±inf/±(s)nan there will be buffer overflows again. Here:

using buffer_type = std::array<char, 2>;
value = -L::quiet_NaN();
std::bfloat16_t
(std  , scientific)	{}	(2, Value too large for defined data type)
(boost, scientific)	BOF!	(9, Success)

(std  , fixed     )	{}	(2, Value too large for defined data type)
(boost, fixed     )	BOF!	(9, Success)

(std  , hex       )	{}	(2, Value too large for defined data type)
(boost, hex       )	{}	(2, Numerical result out of range)

(std  , general   )	{}	(2, Value too large for defined data type)
(boost, general   )	BOF!	(9, Success)

regards
Gero

bit structures/bit_cast

Hello Matt,
I see you are implementing the bit structures twice:
https://github.com/cppalliance/charconv/blob/develop/include/boost/charconv/detail/bit_layouts.hpp
https://github.com/boostorg/math/blob/develop/include/boost/math/ccmath/signbit.hpp

I think it is better to do this only once, for example in boost::math::bits:
bits.hpp.txt
In detail I first provide various bit structures, no matter if they are needed or not. In bits the "normal" bit structures are available.

In https://github.com/boostorg/math/blob/develop/include/boost/math/ccmath/signbit.hpp you still implement BOOST_MATH_BIT_CAST. This is not necessary anymore, because Peter has adapted boost::core::bit_cast
https://github.com/boostorg/core/blob/develop/include/boost/core/bit.hpp
boostorg/core#147 (not quite correct yet)

thx & regards
Gero

Wrong pointer value in from_chars long-double fallback

There is a bug at https://github.com/cppalliance/charconv/blob/06d834728ae8970473f6ef18c079f0e7fae7b071/src/from_chars.cpp#L317

std::strtold is called with a pointer to a temporary std::string and a pointer relative to that is then returned by the function which after the function is invalid/dangling.

It also looks like this is duplicating an existing function that doesn't has this issue and is even better by using a local buffer before falling back to allocating: https://github.com/cppalliance/charconv/blob/06d834728ae8970473f6ef18c079f0e7fae7b071/include/boost/charconv/detail/from_chars_float_impl.hpp#L38 &
https://github.com/cppalliance/charconv/blob/06d834728ae8970473f6ef18c079f0e7fae7b071/include/boost/charconv/detail/from_chars_float_impl.hpp#L101

This should probably be tested too.

Documentation comments from Reuben

Minor comments on documentation:

  • The first example uses to_chars(... sizeof(buffer) - 1), which seems
    to imply a NULL-terminator somewhere. Since there is none, I think it
    should just be sizeof(buffer).
  • Docs don't specify the behavior about NULL-terminators. Either
    specify "adheres to standard" or clarify that no NULL-terminator is
    written.
  • IMO the front page should clearly state that this library is
    compliant with the charconv standard header, noting any exceptions.
  • from_chars overview is missing semicolons in the friends section.
  • Please use monospace in the discussion to refer to identifiers, like
    [first, last).
  • Basic usage: from_chars name is qualified but from_chars_result is not.
  • Code snippets wrap, which makes them difficult to read.

cc: @anarthal

Wrong outputs for FP given precision `to_chars`

Hi, I think the way Boost.Charconv deals with FP to_chars is wrong when the precision is given.

Let's say we do

char buffer[60];
double d = 1e-15;
auto res = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), d,
                     boost::charconv::chars_format::scientific, 50);
*res.ptr = '\0';

The supposed output is the 51 decimal digits of 1e-15 with rounding, in scientific format, which is: 1.00000000000000007770539987666107923830718560119502e-15.

But it seems Boost.Charconv produces 0.000000000000001, which is neither in scientific form nor of 51 digits.

On the other hand, if we do chars_format::general instead, then we get the same output 0.000000000000001 while it's supposed to be 1.0000000000000000777053998766610792383071856011950e-15 (i.e., one less digit due to the inconsistency in how digits are counted between scientific vs general. I'm not sure if the trailing zero in this case is needed/must be removed/doesn't matter... MS STL implementation seems to remove it, but I'm not sure what's the exact requirement.)

Finally, if we do chars_format::fixed instead, then we again get the same output 0.000000000000001 while it's supposed to be 0.00000000000000100000000000000007770539987666107924 (i.e., 50 digits after the decimal dot).

I looked into the implementation and it seems Boost.Charconv invokes dragonbox::to_decimal if the input is in [1e-16,1e16). I am not so sure what was the intention of doing these comparisons, but as far as I understand dragonbox::to_decimal in general will not be enough when the precision is given, especially when it's absurdly large like the case above. (It would be enough when precision is small and the input is normal I think, though.)

The route invoking floff also looks wrong. For instance, let d = 1e-17 instead of 1e-15 and repeat the above three experiments. For the case of chars_format::scientific it works correctly. For the case of chars_format::general, it should produce one less digit again due to different ways of interpreting precision for these two formats, but Boost.Charconv produces identical outputs. For the case of chars_format::fixed, the output must be in the fixed-point form (0.00000000000000001000000000000000071542424054621925) with 50 digits after the decimal dot, but the Boost.Charconv's output is again identical to the case of chars_format::scientific.

Note that floff does not provide an option for fixed-point output, so you can't really treat it as a complete blackbox. I think therefore you have four options at this moment:

  1. Just use the reference implementation of Ryu-printf like other std implementations out there do.
  2. Still use floff as a blackbox but manipulate the precision and the resulting string.
  3. Look into how floff internally works and tweak it into an implementation of fixed-point formatting.
  4. Look for something else, like ones using Dragon4 but without allocation, instead using stack-allocated memory.

I somehow had an impression that you already did the third option... I don't know why. Thinking about it again it sounds like the least manageable option. In my opinion maybe the most efficient option is 1, whose downside is a huge table.

Benchmarks

For a comparison table:

  • Boost.Lexical Cast
  • Boost.Spirit.Qi
  • Boost.Spirit.Karma
  • STL
  • Additionally MSVC STL from_chars to show if it's worth the MSVC team pursuing Lemire's implementation. (microsoft/STL#1610)
  • printf / strtod
  • Google double-conversion https://github.com/google/double-conversion

Doc and README Updates Needed

  • Add from_chars_erange to README
  • Replace cppalliance links with boost links
  • Remove warning that this is in development and not boost

warning with -Wpedantic

GCC complains with pedantic warnings enabled

include/boost/charconv/detail/integer_conversion.hpp|29 col 20| warning: ISO C++ does not support ‘__int128’ for ‘pack’ [-Wpedantic]

Add string_view interface

Several people on slack have asked for a string_view interface in addition to pointer pair. Core is already a dependency and has the convertible string_view in it.

Fix handling of extreme values

The C and C++ standards are clear that for a floating-point type that supports infinities (like IEEE types) all values are in the representable range. So there can never be out of range results (for all implementations supporting IEEE floats, i.e. most of them).

e.g. 1e-9999 should be 0 not ERANGE. It is within range but unrepresentable.

Docs: add tutorial for `limits`

Class limits has its own public header, and appears to be part of the library's interface. But the docs never say what it is for and when and how users are expected to use it.

It looks like in the safe usages users would use its constants to determine the sizes of their buffers. I think the docs should show such real life example.

Documentation comments from Peter Turcan

Charconv Library Documentation review

The documentation is a good start.

Main issues:

  1. Needs a full overview.
  2. Seems like an API Reference section should be organized, combining the
    two from_chars/to_chars sections into one, with API standard type sections
    and subheadings.

Other issues:

  1. Make code/sections clearer with introductory sentences.
  2. Use tables for tabular data, rather than bulleted lists.
  3. All mentions of an API element should link to the page/section on that
    element.
  4. Other notes and suggestions below.

OVERVIEW:

There are three questions to be answered with API docs: What, Why, How - in
that order. The Why question is the most important and usually the most
neglected.

The "What" question ("What makes up the Boost.Charconv library"). For
example: "Boost.Charconv converts character buffers to numbers, and numbers
to character buffers. It is a small library of two overloaded functions to
do the heavy lifting, plus several supporting enums, structures, templates,
and constants, with a particular focus on performance and consistency
across the supported development environments."

The overview really needs to answer the "Why" question: "Why should I [a
C++ developer new to Boost] be interested in this library?". There should
be several paragraphs explaining how it compares with the standard library
and why use this one instead (or as well as perhaps?), and what scenarios
the library is most suited for. A developer who knows nothing about the
library should know at the end of the overview whether this is for them or
not.

If a claim is made, such as "non-allocating", this should be explained with
at least one sentence (no use of malloc perhaps?), and there should be a
note of whether there are exceptions. If there are one or two exceptions
then they can be mentioned by name in the overview. If there are more, add
a sentence that there are exceptions to a general rule, and instead link to
a section listing and explaining those differences.

Is the charconv standard library the opposite: locale-dependent,
allocating, or throwing - if so point that out.

The overview should be upbeat in tone, and should clearly mention
performance.

Dependencies

It is good practice to mention any significant dependencies - on Boost or
other libraries - as part of the overview or part of the initial setup
process. It is good practice too to mention that there are no significant
dependencies.

The rest of the doc should answer the final question, the "How" question:

Usage Examples

Add a sentence stating what the examples do (before each and every code
block), such as "The following examples show a straightforward use of the
two core functions of the library, from_chars and to_chars, converting a
character string to a number (integer or floating point) and converting a
number to a character string. Note that the character string buffer can be
of any length."

Supported Compilers

Good - clear. What about supported Operating Systems?
What about unsupported compilers - does that mean the lib will not work, or
that the lib has not been tested on other compilers? If the latter, perhaps
suggest that it is up to the developer to verify if the lib works correctly
on an unsupported compiler? Would running the benchmarks on an unsupported
compiler do the trick?

Why use Boost.Charconv over ?

Move this up to the Overview with more details - change "several times
faster" to some specific examples. For example using the
Boost.Charconv:from_chars_result function with floating point numbers can
work from 3.23 to 5.77 times faster than the standard library. OK to link
to your benchmarks for more details, but don't require it to answer the Why
question. And are there any areas where this library performs better
generally - floating point numbers, long integers, anything else - then
mention this in the Overview.

Building the Library (perhaps rename to "Getting Started" as it involves
more than just building)

Introduce the section, start with a sentence such as: "The following
section explains how to download and build this library locally on your
development machine."

B2
What if the developer wants to use C++13, does that mean cxxstd=13 should
be set, or should it always be set to 11. Explain any options.

vcpkg
Change "Any required Boost packages that do not already exist will be
installed automatically." to
"Any required Boost packages not currently installed in your development
environment will be installed automatically."

Add the TIP code into the tip itself, if possible, so its indentation is
correct.

from_chars
Add a general title before this something like "API Reference" with an
introductory sentence (though see the notes on Organization below):
"This section describes all the functions, structures, enums, constants,
and macros available in the library." This is generally a good order to
describe an API reference.

Add some text to describe what the source code does or is. Is this the
source code of the function in the library, or perhaps a summarized version
of its definition? Perhaps add a subheading "Definition" or "Syntax".

from_chars_result
The bulleted list of error codes would be better presented as a table with
sub-heading "Return Values" and two columns entitled: "Value" and
"Description" (or similar). This format should be re-used by
to_chars_result.

from_chars [ don't reuse a heading string at the top level] Parameters (or
from_chars Parameters) might be a better title here, or re-organize as
suggested below.
Again, the parameters would be better represented by a table rather than
bullets, with sub-heading Parameters and columns "Name" and "Description".
This format should be re-used by to_chars.

"One known exception is GCC 5 which does not support constexpr comparison
of const char*." - do you have a workaround or suggestion on how to handle
this?

Consider more descriptive headings for:
from_chars for integral types
from_chars for floating point types

  • perhaps
    Usage notes for from_chars with integral types
    Usage notes for from_chars with floating point types

Examples
Integral, Floating Point, Hexadecimal

  • add a sentence preceding each code block describing what is going on, and
    any particular nuances to be aware of
    Same for the invalid arguments - always add a descriptive sentence
    preceding code blocks explaining what is going on.

to_chars

  • same notes as for from_chars

chars_format
Add an intro sentence, noting that this is an enum defining the supported
number formats.

Limits
Add an intro sentence describing what is in this section, and that Limits
are templates (or reorganize as suggested below).
Same notes as above - explain what the Examples are showing, plus nuances

Reference
Not sure what is meant by "Reference" as the above sections appear to be
API reference material. Seems to be a lot of duplication of information
from the above section? Perhaps consider combining the two sections into a
single reference?

References can benefit from being divided up into sections: Functions,
Structures, Enums, Macros, Constants, etc. This makes it clear (from
looking at the table of contents) what the complete contents of the lib are.

Benchmarks

Provide a sentence/paragraph describing the purpose of this section.
Something like:
"This section describes a range of performance benchmarks that have been
run comparing this library with the standard library, and how to run your
own benchmarks if required."

Might need some explanation for libdouble-conversion and {fmt} - such as
"Download the zip file and install the code to your development project" -
or whatever steps are necessary.

Like the use of tables. Is this enough information "to_chars floating point
with the shortest representation" - what is meant by "the shortest
representation"?

Perhaps make it clearer the order of the numbers in Relative Performance -
standard charconv first, then Boost.Charconv second? Just to be completely
clear.

Acknowledgements

Perhaps move "Special thanks to Stephan T. Lavavej for providing the basis
for the benchmarks." to an Acknowledgements section, so you can add more
names as appropriate (testers, design feedback, etc.). A bulleted list
works here.

Sources

Perhaps add an introductory sentence here - not sure that you copied any
algorithms from these but more inspiration and ideas?

Maybe: "The authors acknowledge the inspiration and guidelines from the
following published works." - or similar

Missing Information?:

What about defined constants, such as BOOST_CHARCONV_RUN_BENCHMARKS,
BOOST_CHARCONV_CONSTEXPR - should there be a table of constants defined by
the library - with an explanation of the use of each?

ORGANIZATION and NAVIGATION

Ideally, I would organize the doc into pages (each [page] indicates a new
html page). And ideally the pages are well linked together, for example,
each time from_chars_result is mentioned, it is a link to the page for that
structure. Same for all entries of the functions, structs, enums, etc.

Overview [page]
Intro - answer the What and Why questions
Supported compilers/OS
Getting Started [page]
Downloading and building
Dependencies
Basic usage examples [page]
from_chars examples
to_chars examples
API Reference [page]
toc (table of contents: Functions, Structures, Enumerations, Templates,
Constants, in a table of links)
Functions [page]
toc (table of contents: from_chars, to_chars)
from_chars [page]
overview
definition/syntax (include the library path where the function is
defined)
parameters
return value
remarks/notes [add lower level headings for integers, floating point,
hexadecimal etc. as needed]
examples
to_chars [page]
overview
definition
parameters
return value
remarks/notes
examples
Structures [page]
toc
from_chars_result [page]
overview
definition
fields
remarks/notes
to_chars_result [page]
overview
definition
fields
remarks/notes
Enumerations [page]
toc
chars_format [page]
definition
members
remarks/notes
Templates [page]
toc
Limits [page]
overview
definition
remarks/notes
Constants [page]
table of defined constants with descriptions
Benchmarks
toc
How to run...
Linux
Windows
MacOS
Sources
Acknowledgements
copyright & license

Incompatibility with nan

Hi Matt,
first the code:

template <typename Type>
void	from_and_show(const boost::string_view& view)
{
	Type
		value{};

	{
		const boost::charconv::from_chars_result
			result = boost::charconv::from_chars(view.begin(), view.end(), value);

		std::cout << "boost:";
		if (result.ec == std::errc{})
		{
			std::cout << value;
		}
		else
		{
			std::cout << std::make_error_code(result.ec).message();
		}
	}
	std::cout << '\t';

	//	std::from_chars not support __float128
	BOOST_IF_CONSTEXPR (!std::is_same<Type, boost::float128_type>::value)
	{
		const std::from_chars_result
			result = std::from_chars(view.begin(), view.end(), value);

		std::cout << "std:";
		if (result.ec == std::errc{})
		{
			std::cout << value;
		}
		else
		{
			std::cout << std::make_error_code(result.ec).message();
		}
	}
	std::cout << '\n';
}

template <typename Type>
void	to_and_show(const Type value)
{
	std::array<char, 32>
		string;

	{
		string.fill(0);
		const boost::charconv::to_chars_result
			result = boost::charconv::to_chars(string.begin(), string.end(), value);

		std::cout << "boost:";
		if (result.ec == std::errc{})
		{
			std::cout << string.data();
		}
		else
		{
			std::cout << std::make_error_code(result.ec).message();
		}
	}
	std::cout << '\t';

	//	std::to_chars not support __float128
	BOOST_IF_CONSTEXPR (!std::is_same<Type, boost::float128_type>::value)
	{
		string.fill(0);
		const std::to_chars_result
			result = std::to_chars(string.begin(), string.end(), value);

		std::cout << "std:";
		if (result.ec == std::errc{})
		{
			std::cout << string.data();
		}
		else
		{
			std::cout << std::make_error_code(result.ec).message();
		}
	}
	std::cout << '\n';
}

int main()
{
	const boost::string_view
		nan_pos{"+nan"},
		nan_neg{"-nan"},
		nan{"nan"};

	std::cout << "from nan_pos:\n";
	from_and_show<boost::float128_type>(nan_pos);
	from_and_show<boost::float80_t>(nan_pos);
	from_and_show<boost::float64_t>(nan_pos);
	from_and_show<boost::float32_t>(nan_pos);

	std::cout << "\nfrom nan_neg:\n";
	from_and_show<boost::float128_type>(nan_neg);
	from_and_show<boost::float80_t>(nan_neg);
	from_and_show<boost::float64_t>(nan_neg);
	from_and_show<boost::float32_t>(nan_neg);

	std::cout << "\nfrom nan:\n";
	from_and_show<boost::float128_type>(nan);
	from_and_show<boost::float80_t>(nan);
	from_and_show<boost::float64_t>(nan);
	from_and_show<boost::float32_t>(nan);

	std::cout << "\nto qnan:\n";
	to_and_show(std::numeric_limits<boost::float128_type>::quiet_NaN());
	to_and_show(std::numeric_limits<boost::float80_t>::quiet_NaN());
	to_and_show(std::numeric_limits<boost::float64_t>::quiet_NaN());
	to_and_show(std::numeric_limits<boost::float32_t>::quiet_NaN());

	std::cout << "\nto -qnan:\n";
	to_and_show(-std::numeric_limits<boost::float128_type>::quiet_NaN());
	to_and_show(-std::numeric_limits<boost::float80_t>::quiet_NaN());
	to_and_show(-std::numeric_limits<boost::float64_t>::quiet_NaN());
	to_and_show(-std::numeric_limits<boost::float32_t>::quiet_NaN());

	std::cout << "\nto snan:\n";
	to_and_show(std::numeric_limits<boost::float128_type>::signaling_NaN());
	to_and_show(std::numeric_limits<boost::float80_t>::signaling_NaN());
	to_and_show(std::numeric_limits<boost::float64_t>::signaling_NaN());
	to_and_show(std::numeric_limits<boost::float32_t>::signaling_NaN());

	std::cout << "\nto -snan:\n";
	to_and_show(-std::numeric_limits<boost::float128_type>::signaling_NaN());
	to_and_show(-std::numeric_limits<boost::float80_t>::signaling_NaN());
	to_and_show(-std::numeric_limits<boost::float64_t>::signaling_NaN());
	to_and_show(-std::numeric_limits<boost::float32_t>::signaling_NaN());

	return EXIT_SUCCESS;
}

and the results (gcc):
from nan_pos:
boost:Invalid argument
boost:Invalid argument std:Invalid argument
boost:Invalid argument std:Invalid argument
boost:Invalid argument std:Invalid argument

from nan_neg:
boost:Invalid argument
boost:Invalid argument std:-nan
boost:-nan std:-nan
boost:-nan std:-nan

from nan:
boost:Invalid argument
boost:Invalid argument std:nan
boost:nan std:nan
boost:nan std:nan

to qnan:
boost:nan
boost:nan std:nan
boost:nan std:nan
boost:nan std:nan

to -qnan:
boost:-nan(ind)
boost:-nan(ind) std:-nan
boost:-nan(ind) std:-nan
boost:-nan(ind) std:-nan

to snan:
boost:nan(snan)
boost:nan(snan) std:nan
boost:nan(snan) std:nan
boost:nan(snan) std:nan

to -snan:
boost:-nan(snan)
boost:-nan(snan) std:-nan
boost:-nan(snan) std:-nan
boost:-nan(snan) std:-nan

in general:
from_chars("+nan") is also not supported by the standard (unfortunately).

string values for nan:
These deviate from the standard ("nan"/"-nan"). This is documented https://develop.charconv.cpp.al/#to_chars_to_chars_for_floating_point_types, but boost::charconv is incompatible with it.

from_chars "nan"/"-nan":
boost::float128_type and boost::float80_t -> do not work
boost::float64_t and boost::float32_t -> work

to_chars:
-numeric_limits::quiet_NaN and ±numeric_limits::signaling_NaN -> do not work (see string values)
(+)numeric_limits::quiet_NaN -> works

thx
Gero

Avoid `auto` in docs introduction

The initial docs examples use auto as i n:

auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v);

I recommend spelling out the return type:

boost::charconv::from_chars_result r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v);

It will make it clear for the person that first reads the introduction that the return type is also part of this library, as opposed to using another Boost library or a component from STD.

Some more issues about `to_chars`

  1. It seems that std::to_chars returns errc::value_too_large rather than errc::result_out_of_range. Is this simply a mistake or do you have a reason for using errc::result_out_of_range instead? In the code I edited I used errc::result_out_of_range for consistency.

  2. to_chars with only buffer & value, with the format param as well, and with the precision param as well, all should be separate overloads. The reason why the first and the second should be separate overloads is because the first one should behave differently from the second one with fmt == chars_format::general; it needs to select whatever representation that is shortest, which does not always need to be equal to chars_format::general's output. The reason why the second and the third should be separate overloads is because by the spec, precision being negative should be treated as if precision == 6, because the spec of std::printf says that negative precision is ignored, which means it should fall back to the default, which is 6. I guess this is quite stupid, but well, it seems that's how the spec is written anyway.

EDIT: Ah, forgot to mention. When fixed format is chosen for the shortest representation, the output of Dragonbox may not be the correctly rounded one, because there can be trailing zeros in the integer part. (See fmtlib/fmt#3649 for a related discussion in libfmt.)

Modular Boost C++ Libraries Request

We are in the process of making B2 build changes to all of the B2 build files
to support "modular" consumption of the Boost Libraries by users. See this list
post for some details: https://lists.boost.org/Archives/boost/2024/01/255704.php

The process requires making a variety of changes to make each Boost library
independent of the super-project structure. But the changes do not remove the
super-project structure or the comprehensive Boost release. The changes make
solely make it possible, optionally, for users, like package manages, to easily
consume libraries individually.

Generally the changes include:

  • Adding a libroot/build.jam.
  • Porting any functionality from libroot/jamfile to libroot/build.jam.
  • Moving boost-install declaration from libroot/build/jamfile is applicable.
  • Adjusting other B2 build files in the library, like test/jamfile, as needed.
  • Possible changes to C++ source files to remove includes relative to the
    super-project boostroot location.

Some examples of such changes:

We are asking how you would like us to handle the changes. We would prefer if
you allow the owners of the Boost.org GitHub project to make changes to B2
build files, as needed, to accomplish the changes. But understand
that you may want to manage the proposed changes yourself.

We previously sent emails to all known maintainers to fill out a form with their
preference. We are contacting you in this issue as we have not gotten a response
to that email. You can see the ongoing responses for that form and the responses
to these issues here https://github.com/users/grafikrobot/projects/1/views/6

We are now asking if you can reply directly to this issue to indicate your
preference of handling the changes. Please supply a response to this question
and close the issue (so that we can verify you are a maintainer).

How would you like the build changes to be processed?

  1. Pull request, reviewed and merged by a BOOSTORG OWNER.
  2. Pull request, reviewed and merged by YOU.
  3. Other. (please specify details in the reply)

Also please indicate any special instructions you want us to consider. Or other
information you want us to be aware of.

Thanks you, René

Questions and Comments

Hi Matt,
Questions

  1. supported character types
    I see that you are implementing from_chars_result_t as a template.
    Do you plan to provide from_chars/to_chars for all character types (char32/16/8_t, wchar_t, char)?

  2. multiprecision
    Are from_chars/to_chars also provided for boost::multiprecision types?
    If not, are from_chars/to_chars implemented in boost::multiprecision itself?

Comments

  1. Conversion
    If std::charconv is available I can well imagine that between the types chars_format/from_chars_result/to_chars_result of std::charconv and boost::charconv also times must be converted. You could write functions for this. But I think it makes more sense to provide the boost types with conversions (ctor, cast-operator):
    from_chars_result: from_chars_result.hpp.txt in the template specialization
    to_chars_result: to_chars_result.hpp.txt
    chars_format: chars_format.hpp.txt Unfortunately it is not possible to implement cast operators for enum_a -> enum_b too directly. Therefore I go the way over a struct.

  2. Usage
    If std::charconv is available you can use this.

  3. Comparison operators
    In case you wonder why I adapted the comparison operators; this has the following background:
    gcc very often generates conditional gaps when evaluating the arguments of logical links (&& ||). The result is that the generated code is full of conditional jumps and it increases the code size significantly. This is not cache friendly. In addition, possible cmov's are overlooked/not generated.
    With the "int-trick", the binary linking of the arguments, this does not happen. Of course all arguments are evaluated. If necessary, only exactly one conditional jump is generated.
    This strategy - to generate branchfree code if possible - I find better.

  4. Warnings
    At the moment there are still a lot of warnings (>350) generated concerning conversions Unsigned <-> Signed.

thx
Gero

No standalone

we should only offer one library, the Boost library

Add tests for leading space

A difference of std::from_chars to std::strto* (for both integer and float parsers) is

leading whitespace is not ignored.

I don't see that in the "invalid input" tests. I guess it makes sense to test that too.

And the documentation should cover what the input strings are expected to be. I've found the various format descriptions for floats in an extra section, but none for int. It only states stuff in terms of "matching the pattern", but for ints I wasn't able to find which pattern is used.

warnings

Hi Matt,
in quite a few files there are direct checks for msvc:
#if BOOST_MSVC ...
This generates warnings with other compilers. Please rewrite this to
#if defined(BOOST_MSVC) && (BOOST_MSVC ...)

thx
Gero

various bugs

Hello Matt,
to_chars for std::bfloat16_t is not available

You define BOOST_CHARCONV_HAS_BRAINFLOAT16 in config.hpp, but check for BOOST_CHARCONV_HAS_BFLOAT16 in to_chars.hpp (and for BOOST_CHARCONV_HAS_BRAINFLOAT16 in from_chars.hpp).
Why these error-prone redundancies?

to_chars for FP-Types not work

./Test -nan
gets always -nan(ind)

./Test 3.3
gets

__float128:
std	3.300000	3.300000
boost	3.3000	3.3000

long double:
std	3.300000	3.300000
boost	3.3000	3.3000

double:
std	3.300000	3.300000
boost	3.300000e+00	3.300000e+00

float:
std	3.300000	3.300000
boost	3.300000e+00	3.300000e+00

_Float128:
std	3.300000	3.300000
boost	3.3000	3.3000

_Float64:
std	3.300000	3.300000
boost	3.300000e+00	3.300000e+00

_Float32:
std	3.300000	3.300000
boost	3.300000e+00	3.300000e+00

_Float16:
std	3.300781	3.300781
boost	3.300781e+00	3.300781e+00

std::bfloat16_t:
std	3.296875	3.296875
boost	3.296875e+00	3.296875e+00

Also, to_chars_result.ptr does not always match the actual written values (buffer overflow, hence the double output in print), e.g. compiled with fmt=general:

__float128:
std	3.3	3.3
boost	3.3	3.3

long double:
std	3.3	3.3
boost	3.3
	3.3


double:
std	3.3	3.3
boost	3.3e+00	3.3e+000

float:
std	3.3	3.3
boost	3.3e+00	3.3e+000

_Float128:
std	3.3	3.3
boost	3.3	3.3

_Float64:
std	3.3	3.3
boost	3.3e+00	3.3e+000

_Float32:
std	3.3	3.3
boost	3.3e+00	3.3e+000

_Float16:
std	3.30078	3.30078
boost	3.300781e+00	3.300781e+00

std::bfloat16_t:
std	3.29688	3.29688
boost	3.296875e+00	3.296875e+00

code

namespace test
{
using buffer_type = std::array<char, 1024>;

inline constexpr boost::charconv::chars_format	to_format(const std::chars_format format)	noexcept
{
	switch (format)
	{
		case std::chars_format::scientific:	return boost::charconv::chars_format::scientific;
		case std::chars_format::fixed:		return boost::charconv::chars_format::fixed;
		case std::chars_format::hex:		return boost::charconv::chars_format::hex;
		default:				return boost::charconv::chars_format::general;
	}
}

template <typename Type>
Type get_as(const int argc, const char*const*const args)	noexcept
{
	Type result{};
	if (argc > 1)	[[likely]]
	{
		const std::string_view view(args[1]);
		std::from_chars(view.data(), view.data()+view.size(), result);
	}
	return result;
}

template <typename Type>
inline std::string nameof()
{
	return boost::core::demangle(typeid(Type).name());
}

template <typename Result>
void print(const Result& res, const buffer_type& buf)
{
	if constexpr (std::is_same_v<Result, std::to_chars_result>)	std::cout << "std\t";
	else								std::cout << "boost\t";

	if (res.ec == std::errc{})	[[likely]]	std::cout << std::string_view(buf.data(), res.ptr) << '\t' << buf.data() << std::endl;
	else						std::cout << "error\n";
}

template <std::floating_point Type>
void test_to_chars(const Type value, const std::chars_format format, const int precision)
{
	buffer_type buffer{};
	std::cout << nameof<Type>() << ":\n";
	const auto rs = std::to_chars(buffer.data(), buffer.data()+buffer.size(), value, format, precision);
	print(rs, buffer);
	buffer.fill(char{});
	const auto rb = boost::charconv::to_chars(buffer.data(), buffer.data()+buffer.size(), value, to_format(format), precision);
	print(rb, buffer);
	std::cout << std::endl;
}

}	//	test

int main(const int argc, const char*const*const args)
{
	using namespace test;
	constexpr std::chars_format fmt{std::chars_format::fixed};
	constexpr int pre{6};

	test_to_chars(get_as<boost::float128_t>(argc, args), fmt, pre);
	test_to_chars(get_as<boost::float80_t>(argc, args), fmt, pre);
	test_to_chars(get_as<boost::float64_t>(argc, args), fmt, pre);
	test_to_chars(get_as<boost::float32_t>(argc, args), fmt, pre);

	test_to_chars(get_as<std::float128_t>(argc, args), fmt, pre);
	test_to_chars(get_as<std::float64_t>(argc, args), fmt, pre);
	test_to_chars(get_as<std::float32_t>(argc, args), fmt, pre);
	test_to_chars(get_as<std::float16_t>(argc, args), fmt, pre);
	test_to_chars(get_as<std::bfloat16_t>(argc, args), fmt, pre);

	return EXIT_SUCCESS;
}

thx
Gero

Locale dependence on from_chars fall back

In the instance that from_chars needs to use strtold in an non-"C" locale with a proper "C" locale string it's likely that the value will be returned incorrectly. Also probe strtoflt128 since it's not documented, but I assume it matches strto*.

More failing tests in JSON

The test function: https://github.com/boostorg/json/blob/develop/test/double.cpp#L398

Test data is randomly generated. The number to parse is generated like this:

            unsigned long long x1 = rng();
            unsigned long long x2 = rng();
            int x3 = std::uniform_int_distribution<>( -308, +308 )( rng );

            char buffer[ 128 ];
            sprintf( buffer, "%llu.%llue%d", x1, x2, x3 );

The tests check if the result of the parse is within 2 ULPs from strtod's result.

The output template is

source_string: difference difference ulp
strtod: strtod_output_formatted_as_hexfloat strtod_output_formatted_as_scientific
boost.json: json_output_formatted_as_hexfloat json_output_formatted_as_scientific

My personal obersravtion: almost all failed tests have exponent equal to zero, some have exponent equal to a small negative number (one digit), none have positive exponent.

Abriged test output (800+ tests fail in total):

13037152512515243620.9123444678836069176e0: difference 14783958307161805 ulp
  strtod:       0x1.69da8a45ce200p+63 1.303715251251524e+19
  boost.json:   0x1.217ba1d171b33p+60 1.303715251251524e+18

17697431460539906388.13521888826860801885e0: difference 15239063673179838 ulp
  strtod:       0x1.eb33d04bf49b7p+63 1.769743146053991e+19
  boost.json:   0x1.88f6403cc3af9p+60 1.769743146053991e+18

17947220026488055965.10643827068131766968e0: difference 15263457087823212 ulp
  strtod:       0x1.f222ab0d2131dp+63 1.794722002648806e+19
  boost.json:   0x1.8e822270e75b1p+60 1.794722002648806e+18

11270160277506678000.2887804927902173715e-2: difference 4861924248478836362 ulp
  strtod:       0x1.906582b70668ap+56 1.127016027750668e+17
  boost.json:   0x0.0000000000000p+0 0

16014537415383412664.8126122414435723949e0: difference -4324643243183061970 ulp
  strtod:       0x1.bc7e21dc7c42ep+63 1.601453741538341e+19
  boost.json:   inf inf

12357924155005561639.12442313442625658765e0: difference 14717627412873749 ulp
  strtod:       0x1.5700551678a6dp+63 1.235792415500556e+19
  boost.json:   0x1.1266aa7860858p+60 1.235792415500556e+18

10842998803422154030.17417436331911474420e0: difference 14837738703791900 ulp
  strtod:       0x1.2cf423ed13ed2p+63 1.084299880342215e+19
  boost.json:   0x1.e1869fe1b97b6p+59 1.084299880342215e+18

3296695948989379140.2072548304930659598e0: difference -4335031181509788263 ulp
  strtod:       0x1.6e01bbfddfd99p+61 3.296695948989379e+18
  boost.json:   inf inf

14720212849613461300.6252427338161741728e0: difference 14948319668206553 ulp
  strtod:       0x1.98916730feb3bp+63 1.472021284961346e+19
  boost.json:   0x1.46dab8f3fef62p+60 1.472021284961346e+18

13415429427203554359.6827680959828376040e0: difference 14820899412111836 ulp
  strtod:       0x1.745a5bf8db948p+63 1.341542942720356e+19
  boost.json:   0x1.29e1e32d7c76cp+60 1.341542942720355e+18

16425388162793696488.1428648637494353073e0: difference 15114840694884310 ulp
  strtod:       0x1.c7e567046a72ep+63 1.64253881627937e+19
  boost.json:   0x1.6cb7859d21f58p+60 1.64253881627937e+18

15551626348852379480.895578500933292035e0: difference 15029512392741603 ulp
  strtod:       0x1.afa4f38955e70p+63 1.555162634885238e+19
  boost.json:   0x1.5950c2d444b8dp+60 1.555162634885238e+18

10178294731847607931.4139032688024108114e0: difference 15032476224761005 ulp
  strtod:       0x1.1a8122436e035p+63 1.017829473184761e+19
  boost.json:   0x1.c401d06be3388p+59 1.017829473184761e+18

16884687391751567190.4207240559831443912e0: difference 15159694135212227 ulp
  strtod:       0x1.d4a4eb72a1bcfp+63 1.688468739175157e+19
  boost.json:   0x1.76ea55f54e30cp+60 1.688468739175157e+18

15508783427740974078.9784169047074029632e0: difference 15025328513726817 ulp
  strtod:       0x1.ae7488b789ee7p+63 1.550878342774097e+19
  boost.json:   0x1.585d3a2c6e586p+60 1.550878342774097e+18

4161674219653134848.2773916188372125478e0: difference -4333341770824898115 ulp
  strtod:       0x1.ce09e539ea9bdp+61 4.161674219653135e+18
  boost.json:   inf inf

17046718138251591642.10126573241994849589e0: difference 15175517450300120 ulp
  strtod:       0x1.d92437a8a1638p+63 1.704671813825159e+19
  boost.json:   0x1.7a835fba1ab60p+60 1.704671813825159e+18

17833052686508292662.16607130432395199321e0: difference 15252307933528313 ulp
  strtod:       0x1.eef775dea04dfp+63 1.783305268650829e+19
  boost.json:   0x1.8bf92b18803e6p+60 1.783305268650829e+18

12902599730923774497.3638243857162020647e0: difference -4326162744005552028 ulp
  strtod:       0x1.661e7c3051864p+63 1.290259973092377e+19
  boost.json:   inf inf

17562616406302510556.14203299143330054223e0: difference 15225898140539468 ulp
  strtod:       0x1.e775e5244037ap+63 1.756261640630251e+19
  boost.json:   0x1.85f7ea836692ep+60 1.756261640630251e+18

11124534337803053923.8221091433172228722e0: difference 14755257590203745 ulp
  strtod:       0x1.34c4921470c5dp+63 1.112453433780305e+19
  boost.json:   0x1.ee075020b46fcp+59 1.112453433780305e+18

18376112329591122782.8739648139940204595e0: difference 15305341101798121 ulp
  strtod:       0x1.fe0a219b1be8dp+63 1.837611232959112e+19
  boost.json:   0x1.98081ae27cba4p+60 1.837611232959112e+18

17303681503759734373.13476111557383782824e0: difference 15200611528963025 ulp
  strtod:       0x1.e0460d4c34313p+63 1.730368150375973e+19
  boost.json:   0x1.80380aa35cf42p+60 1.730368150375973e+18

4171777641287505421.15745296356884056941e0: difference -4333322037579518485 ulp
  strtod:       0x1.cf290d4b36debp+61 4.171777641287505e+18
  boost.json:   inf inf

15007638836982346553.17622405128745822208e0: difference 14976388612285545 ulp
  strtod:       0x1.a08bb0044760ep+63 1.500763883698235e+19
  boost.json:   0x1.4d3c8cd0391a5p+60 1.500763883698235e+18

15679947399601163882.9175847862436986831e0: difference 15042043745353789 ulp
  strtod:       0x1.b334ba2b04132p+63 1.567994739960116e+19
  boost.json:   0x1.5c2a2e88d00f5p+60 1.567994739960116e+18

1375625481728964437.3257470654421881132e0: difference -4340600103374524873 ulp
  strtod:       0x1.3173416566e37p+60 1.375625481728964e+18
  boost.json:   inf inf

17522151151592932105.3192661631912476227e0: difference 15221946455509235 ulp
  strtod:       0x1.e6565f45a6cc0p+63 1.752215115159293e+19
  boost.json:   0x1.8511e5d1523cdp+60 1.752215115159293e+18

10904266218413608595.11601234078016542213e0: difference 14819789265806122 ulp
  strtod:       0x1.2ea778b469abap+63 1.090426621841361e+19
  boost.json:   0x1.e43f27870f790p+59 1.090426621841361e+18

11536133438290722858.3167973823142988657e0: difference 14637374413194566 ulp
  strtod:       0x1.4031287b6da60p+63 1.153613343829072e+19
  boost.json:   0x1.00275395f151ap+60 1.153613343829072e+18

15812369546801428021.676415907514195163e0: difference 15054975595666315 ulp
  strtod:       0x1.b6e1a4a68c9b7p+63 1.581236954680143e+19
  boost.json:   0x1.5f1aea1ed6e2cp+60 1.581236954680143e+18

10785418902967488452.4135477779533264455e0: difference 14854607815253228 ulp
  strtod:       0x1.2b5b02b282522p+63 1.078541890296749e+19
  boost.json:   0x1.def80450d0836p+59 1.078541890296749e+18

17725096521973075874.10939473679303342849e0: difference 15241765339335421 ulp
  strtod:       0x1.ebf862c0136f2p+63 1.772509652197308e+19
  boost.json:   0x1.8993823342bf5p+60 1.772509652197308e+18

18213197810053703865.16826757387480770172e0: difference 15289431480749545 ulp
  strtod:       0x1.f9848dd23858dp+63 1.82131978100537e+19
  boost.json:   0x1.946a0b0e937a4p+60 1.82131978100537e+18

11950260987498944012.6386608747976736054e0: difference 14677816556671932 ulp
  strtod:       0x1.4bafb61b1a2abp+63 1.195026098749894e+19
  boost.json:   0x1.09595e7c14eefp+60 1.195026098749894e+18

18435124945933098595.1350387634451383774e0: difference 15311104052612767 ulp
  strtod:       0x1.ffad70ee0091cp+63 1.84351249459331e+19
  boost.json:   0x1.99578d8b33a7dp+60 1.84351249459331e+18

15732155702845141543.12170084634184239293e0: difference 15047142212467459 ulp
  strtod:       0x1.b4a7b084b670ep+63 1.573215570284514e+19
  boost.json:   0x1.5d52f39d5ec0bp+60 1.573215570284514e+18

14735145692382608385.13721209258082999052e0: difference 14949777953633228 ulp
  strtod:       0x1.98fb81dfc82f8p+63 1.473514569238261e+19
  boost.json:   0x1.472f9b196cf2cp+60 1.473514569238261e+18

16843845449241599091.3645101603587738312e0: difference 15155705664263988 ulp
  strtod:       0x1.d382b8631b404p+63 1.68438454492416e+19
  boost.json:   0x1.76022d1c15cd0p+60 1.68438454492416e+18

13728498331271665810.9173772052889383142e0: difference -4325759473204600909 ulp
  strtod:       0x1.7d0ad8fdbdfb3p+63 1.372849833127167e+19
  boost.json:   inf inf

7727263384834318767.15818157836697797250e0: difference -4329420285508535384 ulp
  strtod:       0x1.acf3046e4bba8p+62 7.727263384834318e+18
  boost.json:   inf inf

10706017860980947897.10919070792848914143e0: difference 14877869839272721 ulp
  strtod:       0x1.2926d50b15837p+63 1.070601786098095e+19
  boost.json:   0x1.db7154de88d26p+59 1.070601786098095e+18

10654154846154977666.13474161817864302486e0: difference 14893064081897518 ulp
  strtod:       0x1.27b652c4d625ep+63 1.065415484615498e+19
  boost.json:   0x1.d923b7a156a30p+59 1.065415484615498e+18

10679211027982662991.3553476966102005076e0: difference 14885723403627689 ulp
  strtod:       0x1.28685bb2b8ae8p+63 1.067921102798266e+19
  boost.json:   0x1.da4092b78de3fp+59 1.067921102798266e+18

16709350569134734862.10502183930325098237e0: difference 15142571398628552 ulp
  strtod:       0x1.cfc713a0197e8p+63 1.670935056913474e+19
  boost.json:   0x1.7305a94ce1320p+60 1.670935056913474e+18

16462365524966446931.10878889807662127244e0: difference 15118451765408993 ulp
  strtod:       0x1.c8ec24727c863p+63 1.646236552496645e+19
  boost.json:   0x1.6d89b6c1fd382p+60 1.646236552496645e+18

16259249861213631764.10036525128987826459e0: difference 15098616251370632 ulp
  strtod:       0x1.c348eb3507ea7p+63 1.625924986121363e+19
  boost.json:   0x1.69072290d321fp+60 1.625924986121363e+18

13238618194926065003.11600368111639048145e-4: difference 4833154247819142138 ulp
  strtod:       0x1.2d02e65ee23fap+50 1323861819492606
  boost.json:   0x0.0000000000000p+0 0

16425993616894296297.11242468553826483552e0: difference 15114899821261322 ulp
  strtod:       0x1.c7e9b454f3a30p+63 1.64259936168943e+19
  boost.json:   0x1.6cbaf6aa5c826p+60 1.64259936168943e+18

15273281031176574834.10612599083659480591e0: difference 15002330232812325 ulp
  strtod:       0x1.a7eb305a63fbbp+63 1.527328103117657e+19
  boost.json:   0x1.53228d151cc96p+60 1.527328103117658e+18

18206574149764647052.17549221604765645903e0: difference 15288784638924442 ulp
  strtod:       0x1.f9557d740b101p+63 1.820657414976465e+19
  boost.json:   0x1.9444645cd5a67p+60 1.820657414976465e+18

15506626813000530246.8152389634815566227e0: difference 15025117906818571 ulp
  strtod:       0x1.ae6535db8ae37p+63 1.550662681300053e+19
  boost.json:   0x1.5850f7e2d582cp+60 1.550662681300053e+18

128-bit to_chars not giving shortest representation

Examples:

Value: 0.4851437654714521865648158005512869
Boost: 4.851437654714521865648158005512869e-01
  STL: 0.4851437654714521865648158005512869
Value: 0.007103704461770353364817587316082381
Boost: 7.103704461770353364817587316082381e-03
  STL: 0.007103704461770353364817587316082381

For small negative exponents we should be using fixed formatting not scientific.

from_chars test failures in JSON

I'm experimenting with using this library in Boost.JSON. I get these errors from from_chars:

Invalid argument [generic:22 at ../../boost/json/basic_parser_impl.hpp:2691 in function 'parse_number'] after 3 characters of 0E0
Invalid argument [generic:22 at ../../boost/json/basic_parser_impl.hpp:2691 in function 'parse_number'] after 4 characters of 0E01
Invalid argument [generic:22 at ../../boost/json/basic_parser_impl.hpp:2691 in function 'parse_number'] after 5 characters of 0.0e0
Invalid argument [generic:22 at ../../boost/json/basic_parser_impl.hpp:2691 in function 'parse_number'] after 4 characters of -0E0
Invalid argument [generic:22 at ../../boost/json/basic_parser_impl.hpp:2691 in function 'parse_number'] after 5 characters of -0E01
Invalid argument [generic:22 at ../../boost/json/basic_parser_impl.hpp:2691 in function 'parse_number'] after 6 characters of -0.0e0

from_chars for boost::int128_type not work

Hi Matt,
from_chars for boost::int128_type does not work if the string values are smaller/larger than min/max:

template <typename Type>
void test_from_chars(const std::string_view& view)
{
	Type
		v1{0}, v2{0};

	std::cout << view << ":\n";
	std::from_chars(view.data(), view.data()+view.size(), v1);
	std::cout << "std\t" << v1 << '\n';
	boost::charconv::from_chars(view.data(), view.data()+view.size(), v2);
	std::cout << "boost\t" << v2 << '\n';
	std::cout << "equal\t" << (v1==v2) << "\n\n";
}

test_from_chars<boost::int128_type>( "170141183460469231731687303715884105728");	//	max+1
test_from_chars<boost::int128_type>("-170141183460469231731687303715884105729");	//	min-1

gets

170141183460469231731687303715884105728:
std 0
boost -170141183460469231731687303715884105728
equal false

-170141183460469231731687303715884105729:
std 0
boost 170141183460469231731687303715884105727
equal false

thx
Gero

to_chars hex FP80

Test value: -35896.53987658756543653653365436f128

FP80
hex not work
(std , hex ) -8.c388a355a1f783ap+12 (22, Success)
(boost, hex ) -1.0000000000000c388ap+81950 (28, Success)

FP16
scientific different precision
(std , scientific) -3.59e+04 (9, Success)
(boost, scientific) -3.5904e+04 (11, Success)

BF16
scientific different precision
(std , scientific) -3.59e+04 (9, Success)
(boost, scientific) -3.5904e+04 (11, Success)

`from_chars` incompatible with `std::from_chars`

The following behavior is described in from_chars for floating point types:

On std::errc::result_out_of_range we return ±0 for small values (e.g. 1.0e-99999) or ±HUGE_VAL for large values (e.g. 1.0e+99999) to match the handling of std::strtod. This is a divergence from the standard which states we should return the value argument unmodified.

This divergence from std::from_chars is unacceptable in a library that claims to be a faster replacement for the STD component. std::from_chars gives a practical guarantee: either we populated the new value as per your request, or we didn't touch your value. One can easily imagine how this strong (commit-or-rollback) error guarantee is useful. And it will silently disappear when someone replaces std::from_chars with boost::from_chars for efficiency.

`to_chars_hex` for __float128 incorrect exp

Test value: -3.589653987658756543653653365436e+04

(std  , hex       )	-1.1871146ab43ef0735e163704ac67p+15	(35, Success)
(boost, hex       )	-1.1871146ab43ef0735e163704ac67p+32783	(38, Success)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.