I have a library which needs to parse double numbers which always use a point '.' as decimal separator. Unfortunately for this case, strtod() respects the locale which might use a different separator and thus parsing can fail. I can't setlocale() - it isn't thread-safe. So I'm searching for a clean locale-independent strtod implementation now. I have found multiple implementations so far, but all of them look hacky or just like bad code. Can someone recommend a well-tested, working, clean (ANSI) C implementation for me?
Grab some known implementation (that doesn't depend on atof
), such as the one distributed with ruby:
ruby_1_8/missing/strtod.c.
Warning: The proposed implementation from ruby contains bugs. I wouldn't mind the small difference pointed out by gavin, but if you try to parse something like "0.000000000000000000000000000000000000783475" you will get 0.0 instead of 7.834750e-37 (like the stock strtod() returns.)
Other solution:
#include <sstream>
#include "strtod_locale_independent.h"
extern "C" double strtod_locale_independent(const char* s)
{
std::istringstream text( s );
text.imbue(std::locale::classic());
double result;
text >> result;
return result;
}
I don't know how fast this is, though.
Following the answer above, I tried using the Ruby implementation at ruby_1_8/missing/strtod.c. However, for some inputs this gives different answers to gcc's built-in parser and to strtod from stdlib.h, both on Mac and on Linux platforms:
char * endptr ;
double value1 = 1.15507e-173 ;
double value2 = strtod( "1.15507e-173", &endptr ) ;
double value3 = test_strtod( "1.15507e-173", &endptr ) ;
assert( sizeof( double ) == sizeof( unsigned long ) ) ;
printf( "value1 = %lg, 0x%lx.\n", value1, *(unsigned long*)( &value1 ) ) ;
printf( "value2 = %lg, 0x%lx.\n", value2, *(unsigned long*)( &value2 ) ) ;
printf( "value3 = %lg, 0x%lx.\n", value2, *(unsigned long*)( &value3 ) ) ;
assert( value1 == value2 ) ;
assert( value1 == value3 ) ;
which prints
value1 = 1.15507e-173, 0x1c06dace8bda0ee0.
value2 = 1.15507e-173, 0x1c06dace8bda0ee0.
value3 = 1.15507e-173, 0x1c06dace8bda0edf.
Assertion failed: (value1 == value3), function main, file main.c, line 16.
So my advice is to test the chosen implementation before use.
There's also gdtoa available on netlib, BSD style license: http://www.netlib.org/fp/gdtoa.tgz
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With