Opened 11 years ago

Closed 11 years ago

#6571 closed Bugs (fixed)

lexical_case<float>(someString) does not recognize IEEE exceptions

Reported by: Chromatix <mhazadmanesh2009@…> Owned by: Antony Polukhin
Milestone: To Be Determined Component: lexical_cast
Version: Boost 1.50.0 Severity: Problem
Keywords: Cc:

Description

When using lexical_cast to cast a floating point value (float, double, long double), lexical_cast will generate the proper IEEE floating-point exception string. But when converting the string representation to the real floating point value, lexical_cast doesn't recognize the special values and throws bad_lexical_cast. Look at this example trying to work with double undefined values. The same problem exists for infinity (and probably for other special values that I'm not aware of).

#include <boost/lexical_cast.hpp>
int main()
{
    boost::lexical_cast<string>(sqrt(-1.0)); //OK, returns "-1.#IND"
    boost::lexical_cast<double>("-1.#IND");  //bad_lexical_cast !!!
    return 0;
}

Change History (9)

comment:1 by Chromatix <mhazadmanesh2009@…>, 11 years ago

Summary: lexical_case<double>(someString) does not recognize IEEE exceptionslexical_case<float>(someString) does not recognize IEEE exceptions

comment:2 by Antony Polukhin, 11 years ago

Status: newassigned

I`ve tested on GCC compiler, and

boost::lexical_cast<string>(sqrt(-1.0)); 

returns "-nan", which is correct according to standard.

Please, tell me about the compiler you are using.

in reply to:  2 comment:3 by Chromatix <mhazadmanesh2009@…>, 11 years ago

As my comments in the example code show, converting to string or char* is always OK. Problem arises when you want to convert the string representation of the error into a floating point type (say, double). For example trying to lexical_cast the above result ("-nan" in GCC, "-1.#IND" in MSVC) to a double throws bad_lexical_cast instead of returning a double containing that special value.

comment:4 by Antony Polukhin, 11 years ago

I`ve tested boost_1.48 on VC10 and boost::lexical_cast<string>(sqrt(-1.0)); output is '-nan'.

"-1.#IND" is not a standard, but rather a compiler specific extension. Lexical_cast will not support it.

You can use lexical_cast everywhere and have a cross platform portable behavior. Or you can wrap around lexical_cast function and use that wrapper to support compiler extensions, violating standard.

comment:5 by Chromatix <mhazadmanesh2009@…>, 11 years ago

I'm not specifically speaking about -1.#IND. lexical_cast fails to convert -nan and inf from a string type to their floating point values too.

If lexical_cast is able to successfully convert the double undefined value to its string representation (-1.#IND, -nan, etc) then it must also be able to do the vice versa without throwing errors, No?

If you're wondering why it makes sense to implement such a conversion: I'm working on a program that frequently reads/writes double's to/from file. In the program calculations, sometimes undefined or infinity values are generated (which are fine and sometimes necessary in the program's logic). Now I have no problem saving them to disk (since lexical_cast<string>(someUndefinedDouble) works) but can't read them back (since e.g lexical_cast<double>("-nan") fails).

comment:6 by Antony Polukhin, 11 years ago

Lets start from the beginning:
1) I`ve tested lexical_cast<double>("-nan") on VC10 and it passed
2) I`ve tested boost::lexical_cast<string>(sqrt(-1.0)); on VC10 and it passed and outputteed "-nan"
3) There are about 90 tests on nan/inf and they pass: tests, results1, results2. And they are passing since boost_1.48

I can not reproduce your error, so please can you answer the following questions:
1) Which version of boost are you using exactly? Is it boost_1.47, is it boost_1.48?
2) Which compiler exactly are you using? Is it Visual Studio 2010, is it Visual Studio 2003?
3) Reproduce the error on your compilerand copypaste the code that produces error to this ticket.

comment:7 by Chromatix <mhazadmanesh2009@…>, 11 years ago

Oops, it seems I mixed up boost versions.

My boost on Windows was 1.47 which is why boost::lexical_cast<string>(sqrt(-1.0)) returned -1.#IND on Visual Studio (it's 2010 btw). On 1.48 it returns -nan and can be converted back to double.
So a major part of this bug report doesn't make sense now. Sorry about the mistake here. :(

However, the title question still makes sense about -1.#IND. Neither nan nor -1.#IND are global standards. -nan is the standard on *nix (and GCC on windows), but all Microsoft compilers (since VS5 and even before that I guess) represent the error value as -1.#IND, 1.#QNAN, etc. (Simply try cout << sqrt(-1.0)). So I think it's essential to implement such a conversion: boost::lexical_cast<double>("-1.#IND") to work. Since with a Microsoft compiler one might occasionally encounter the -1.#IND and other error strings generated by conversion methods other than boost::lexical_cast or from external libraries.

I also found this: http://en.wikipedia.org/wiki/NaN#Display.

comment:8 by Antony Polukhin, 11 years ago

There is a formal specification for Not-A-Number strings in C. According to standard strtod, strtof, and strtold, scanf, sscanf and fscanf functions must parse NaN like that:

The expected form of the subject sequence is an optional plus or minus sign, then one of
the following:
— INF or INFINITY, ignoring case
— NAN or NAN(n-char-sequenceopt), ignoring case in the NAN part, where:
...

C++ stream operators use those functions for conversion.

I`ll add your questions to the lexical_cast documentation (FAQ section).

comment:9 by Antony Polukhin, 11 years ago

Resolution: fixed
Status: assignedclosed
Version: Boost 1.48.0Boost 1.50.0

Documentation updated in r77118.

Note: See TracTickets for help on using tickets.