Re: float to string to float, with first float == second float
On Oct 6, 2:28 pm, Rune Allnor <all...@tele.ntnu.no> wrote:
On 6 Okt, 15:14, Carsten Fuchs <CarstenFu...@T-Online.de> wrote:
Rune Allnor wrote:
Output:
a = 0.3
b = 0.300000011921
There are two problems here:
1) Numbers that are exact in decimal notation
have no exact floating-point representation,
only an approximation.
I understand this, but all I'm looking for is a
serialization of "a" that, when converted back to a float,
yields the same bits for "a" again.
That is, I don't care about the fact that
float a=0.3;
doesn't assign the exact decimal value 0.3 to "a". Due to
the inherent limits of floating point representations,
exactly as you pointed out, the "true" value of "a" will
*not* be 0.3.
The problem is to come up with a pattern that is guaranteed
to reproduce the original binary pattern:
1) Approximations might occur when the value is first loaded
2) Approximations might occur when the value is serialized
3) Approximations might occur when the value is de-serialized
The problem is steps 2) and 3): Unless you can guarantee
that either
a) No approximations occur in steps 2) and 3)
b) The approximation in 3) exactly cancels the
approximation introduced in 2)
you can not guarantee that you end up with the same bit
pattern as you started out with.
With IEEE floating point, b is guaranteed for "normal" numbers
if there are at least 9 decimal digits. (I looked it up this
time---my original statement that 7 suffices was wrong.) There
may be problems with +/-0.0, if e.g. the implementation always
outputs 0.0 (even for a negative 0), or reads -0.0 as a positive
zero, and of course, nothing is said about infinity and NaNs.
But again, this is not what I'm after.
Instead, I'm looking for
float a2 = unserialize(serialize(a));
such that a2==a (fully intentionally using the == comparison with floats).
Understanding the term 'serialize' as 'store binary data on
text-based format', I would have dropped the requirement for
human readability and stored the HEX pattern of the float.
Why? The whole point of using text instead of binary is human
readability. Of course, human readability isn't a binary
condition; there's a range for something like:
1.9
1.899999976
15938355*2^-23
3FF33333
All of the above are output from the same float, initialized
with the floating point literal 1.9. The first is the default
format, the second using fixed and a precision of 9, the third
using:
std::string
asInts( float const& f )
{
unsigned const& p = reinterpret_cast<unsigned const&>(f);
int sign = (p & 0x80000000) == 0 ? 1 : -1;
int exponent = ((p & 0x7F800000) >> 23) - 127 - 23;
int mantissa = (p & 0x007FFFFF) | 0x00800000;
while ( (mantissa & 1) == 0 ) {
mantissa >>= 1;
++ exponent;
}
std::ostringstream result ;
result << mantissa*sign << "*2^" << exponent ;
return result.str() ;
}
and the last a simple hex dump of the bytes. The last two are
an exact representation, and the last three guarantee round trip
conversion.
Something like
#include<iomanip>
float a = 0.3;
ss << std::hex() << a << std::endl;
ss >> std::hex() >> a;
should go a long way to meet your requirements - EXCEPT
for the 'human readability' issue.
And the fact that std::hex doesn't affect floating point
output:-). To get the output I have above, I used:
ss.setf( std::ios::hex, std::ios::basefield );
ss.setf( std::ios::uppercase );
ss << std::setw(8) << reinterpret_cast<unsigned const&>(a);
--
James Kanze