views:

244

answers:

2

I'm working on a cross-platform app for Windows and Mac OS X, and I have a problem with two standard C library functions:

  • strtod() - string-to-double conversion
  • sprintf() - when used for outputting double-precision floating point numbers)

Their GCC and MSVC versions return different results, in some digits of mantissa. But it plays a cruicial role if the exponent value is large. An example:

MSVC: 9,999999999999999500000000000000e+032
GCC:  9,999999999999999455752309870428e+32
MSVC: 9,999999999999999500000000000000e+033
GCC:  9,999999999999999455752309870428e+33
MSVC: 9,999999999999999700000000000000e+034
GCC:  9,999999999999999686336610791798e+34

The input test numbers have an identical binary representation under MSVC and GCC.

I'm looking for a well-tested cross-platform open-source implementation of those functions, or just for a pair of functions that would correctly and consistently convert double to string and back.

I've already tried the clib GCC implementation, but the code is too long and too dependent on other source files, so I expect the adaptation to be difficult.

What implementations of string-to-double and double-to-string functions would you recommend?

+2  A: 

Converting between floating point numbers and strings is hard - very hard. There are numerous papers on the subject, including:

The last of those is a treasure trove of information on floating point decimal arithmetic.

The GNU glibc implementation is likely to be about as good as it gets - but it won't be short or simple.


Addressing examples

A double normally stores 16 (some might argue 17) significant decimal digits. MSVC is processing 17 digits. Anything beyond that is noise. GCC is doing as you ask it, but there aren't enough bits in a double to warrant the extra 14 digits you are requesting. If you had 16-byte 'long double' values (SPARC, PPC, Intel x86_64 for Mac), then you might warrant 32 significant figures. However, the differences you are showing are QoI; I might even argue that MS is doing a better job than GCC/glibc here (and I don't often say that!).

Jonathan Leffler
Even if results of floating point operations are non-exact, each floating point value corresponds to a specific exact diadic rational number. A good algorithm for printing floating point values will be able to print this exact number. A satisfactory (according to standards) algorithm will print it with enough significant digits to uniquely determine what the original floating point value was.
R..
I'm with Jonathan. A satisfactory (and standards compliant) algorithm will print enough significant digits to uniquely determine the original value (both GCC and MSVC manage this). A good algorithm will also round the decimal result to approximately the same precision as the least significant bit in the binary representation to avoid implying that the result is more precise than the binary representation allows.
Stephen C. Steel
A: 

The only algorithm I know for printing the exact value of a floating point number in decimal is as follows:

  1. Convert the mantissa to a decimal integer. You can either do this by pulling apart the bits to read the mantissa directly, or you can write a messy floating point loop that first multiplies the value by a power of two to put it in the range 1<=x<10, then pulls off a digit at a time by casting to int, subtracting, and multiplying by 10.
  2. Apply the exponent by repeatedly multiplying or dividing by 2. This is an operation on the string of decimal digits you generated. Every ~3 multiplications will add an extra digit to the left. Every single dividion will add an extra digit to the right.

It's slow and ugly but it works...

R..