Boost logo

Boost Users :

Subject: Re: [Boost-users] [lexical_cast] float-to-string rounding error (notfound with cout)
From: OvermindDL1 (overminddl1_at_[hidden])
Date: 2009-04-30 15:33:18


On Thu, Apr 30, 2009 at 11:49 AM, Grant Birchmeier
<gbirchmeier_at_[hidden]> wrote:
> On Thu, Apr 30, 2009 at 12:20 PM, Peter Dimov <pdimov_at_[hidden]> wrote:
>>> (1) Is there a way to eliminate this trailing '1' with lexical_cast
>>> (presumably some wierd rounding error)?
>>
>> Try this code:
>>
>
>>   std::cout << f2 << std::endl;
>>   std::cout << boost::lexical_cast<std::string>(f2) << std::endl;
>>
>>   std::cout << f - f2 << std::endl;
>>
>> which will hopefully answer your question.
>
> The resulting output from your code, Peter, is:
> 123.123
> 123.123001
> 123.123
> 123.123001
> 0
>
> That's just great.  So internally (on my system, anyway) the two
> floats are equal, and the two methods of converting it to string just
> round it differently.  Curses.

It might help to read up on the IEEE floating point standards.
Basically 'most' floating point numbers you will give a computer are
incapable of being representing accurately by the CPU in just 32-bits
(there are a couple bignum floating point libraries that retain
accuracy quite well, obviously much slower). std::cout was just
truncating the printed value (which you can control by passing an
attribute to the stream to, say, not do any rounding/truncation).
Boost.Lexical_cast uses StreamStream internally, and rounding seems to
be off, which is good because then it represents the internal number
accurately when printed.

This is also why you *NEVER* (and this is important enough to say
again, ***NEVER***) directly compare floats for equality, there can be
arbitrary accuracy in the number.

Example:
bool FloatsEqual(float f1, float f2)
{
    return f1=f2;
}

A more proper implementation would be:
bool FloatsEqual(float f1, float f2, float eps=0.00001)
{
    return eps>(f1-f2);
}

The second implementation does a subtraction first to get them to as
close to zero as possible if they are near equal. And if the floats
had a lot of operations on them and their representations got off (try
comparing ((1-0.33333)+0.66666)==1.0 without constant folding... it
fails, the left ends up being 0.999998 or so), this will let you pass
an 'accuracy' value, the epsilon (there is also an epsilon calculation
function in the std namespace).

So instead of
if(f1==f2) {...
You should do something like (with whatever accuracy you want):
if(0.00001<(f1-f2)) {...


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net