Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Comparing double in for loop

Reply
Thread Tools

Comparing double in for loop

 
 
eman.abu.samra@gmail.com
Guest
Posts: n/a
 
      04-09-2008
Hi all,

i have encountered the strangest behavior. Check out this simple
program:

#include <stdio.h>

int main()
{
double time = 1;
double i = 0;

for (double i = 0; i < time ; i+=0.01 )
{
if ( i == 0.15 )
{
printf( "found %f\n", i);
}
if ( i < 0.1 )
{
printf( "foundXX %f\n", i);
}
}

return 1;
}

What would you expect to be printed:
All the numbers from 0.0 to 0.9 with the prefex: foundXX
and last line in output should be found 0.15 - right?!
Wrong... what I get is all the numbers from 0.0 to 0.1 printed
(including 0.1!!)
When checking if ( i==0.1) { printf( "foundXX %f\n",i);} it does not
print foundXX 0.1!!
Why exactly does it think that 0.1 is < than 0.1!!??

anyone?

Thanks
 
Reply With Quote
 
 
 
 
Tim Love
Guest
Posts: n/a
 
      04-09-2008
http://www.velocityreviews.com/forums/(E-Mail Removed) writes:

>Hi all,


>i have encountered the strangest behavior.

See
http://www.eason.com/library/math/floatingmath.pdf
or (easier and more appropriate for your problem)
http://www.mathworks.com/company/new...all96Cleve.pdf
 
Reply With Quote
 
 
 
 
Michael.Boehnisch@gmail.com
Guest
Posts: n/a
 
      04-09-2008
On 9 Apr., 15:26, (E-Mail Removed) wrote:
> i have encountered the strangest behavior. Check out this simple
> program:

[..]
> What would you expect to be printed:
> All the numbers from 0.0 to 0.9 with the prefex: foundXX
> and last line in output should be found 0.15 - right?!
> Wrong... what I get is all the numbers from 0.0 to 0.1 printed
> (including 0.1!!)


The number 0.1 is not representable in the internal format for double
numbers of your compiler, see for example IEEE-754. In binary format,
0.1 has a infinite length periodic mantissa:
0.1 (10) == 0.00011001100110011... (2), with a period length of four
digits. This is analog to 1/3 with base 10: 1/3 = 0,33333... (10) and
with base 3 it is just 0.1 (3), no periodic repetition.

The compiler selects the closest match it can store internally which
is off by ~10^(-1 for Visual C++ 2005. Your repeated adding of this
only-nearly-0.1 number accumulates an error that gives you the
"strange" behavior. Machine double numbers are a finite subset of the
infinite real number domain. The operations on them executed by a
computer are similar but not identical to the math +, -, *, /, ...
operators 0.1 + 0.1 + 0.1 + 0.1 + 0.1 .

You should not check identity of two doubles like in "if ( i ==
0.15 ) ...". Better define a error margin, eg:

const double eps = 1E-9;
if ( i < 0.15 + eps && i > 0.15 - eps ) ...

This will save you from some nasty surprises in real applications.
Note, you should adapt eps according to your expected accumulated
error, depending on the operations you executed before, 10^(-9) may be
to small or too large.

> When checking if ( i==0.1) { printf( "foundXX %f\n",i);} it does not
> print foundXX 0.1!!
> Why exactly does it think that 0.1 is < than 0.1!!??


Try a variation on the 2nd printf() in your code:

printf( "foundXX %20.18lf (%20.18lf)\n", i, i - 0.1 );

> Thanks


My pleasure.

Michael.
 
Reply With Quote
 
Matthias Buelow
Guest
Posts: n/a
 
      04-09-2008
Tim Love wrote:

> http://www.eason.com/library/math/floatingmath.pdf
> or (easier and more appropriate for your problem)
> http://www.mathworks.com/company/new...all96Cleve.pdf


Good reading material. For a quick answer:

http://www.parashift.com/c++-faq-lit...html#faq-29.17
 
Reply With Quote
 
Juha Nieminen
Guest
Posts: n/a
 
      04-09-2008
(E-Mail Removed) wrote:
> for (double i = 0; i < time ; i+=0.01 )
> {
> if ( i == 0.15 )
> {
> printf( "found %f\n", i);
> }
> if ( i < 0.1 )
> {
> printf( "foundXX %f\n", i);
> }
> }


As others have pointed out, 0.01 cannot be represented accurately with
floating point numbers (for the same reason as eg. 1/3 cannot be
represented accurately with decimal numbers).

Clearly you want a precise number of iterations to your loop, and you
want precise control on what happens with some precise values of the
loop counter. In those cases what you should do is to use an integer
loop counter, and calculate the floating point value from it. In other
words:

for(int i = 0; i < 100; ++i)
{
double value = i/100.0;

if(i == 15) std::cout << "found " << value << "\n";
if(i < 10) std::cout << "foundXX " << value << "\n";
}

The integer loop counter will make sure that an accurate number of
iterations is performed, and comparing this integer loop counter in the
conditionals will make sure that those conditionals give an accurate
result. Whenever the floating-point value needs to be used, use the
'value' variable, as exemplified above.
 
Reply With Quote
 
Ioannis Vranos
Guest
Posts: n/a
 
      04-09-2008
(E-Mail Removed) wrote:
> Machine double numbers are a finite subset of the
> infinite real number domain. The operations on them executed by a
> computer are similar but not identical to the math +, -, *, /, ...
> operators 0.1 + 0.1 + 0.1 + 0.1 + 0.1 .



Then why doesn't an implementation use a large number of bits, for
people that want accuracy and also for x==y to work?


Like 8,000 bits or 8,000,000 bits or any number of bits necessary to
store all the possible numbers for double for example.
 
Reply With Quote
 
Jim Langston
Guest
Posts: n/a
 
      04-10-2008
"Ioannis Vranos" <(E-Mail Removed)> wrote in message
news:ftjkmb$2dbu$(E-Mail Removed)...
> (E-Mail Removed) wrote:
>> Machine double numbers are a finite subset of the
>> infinite real number domain. The operations on them executed by a
>> computer are similar but not identical to the math +, -, *, /, ...
>> operators 0.1 + 0.1 + 0.1 + 0.1 + 0.1 .

>
>
> Then why doesn't an implementation use a large number of bits, for
> people that want accuracy and also for x==y to work?
>
>
> Like 8,000 bits or 8,000,000 bits or any number of bits necessary to
> store all the possible numbers for double for example.


Since 0.1 in binary is an infinate regression, it would take an infinite
number of bits to represent it.

--
Jim Langston
(E-Mail Removed)


 
Reply With Quote
 
Juha Nieminen
Guest
Posts: n/a
 
      04-10-2008
Ioannis Vranos wrote:
> Then why doesn't an implementation use a large number of bits, for
> people that want accuracy and also for x==y to work?


Sure, if you want your program to be a thousand times slower.

The C++ compiler will usually use the FPU (and sometimes even SSE) to
make floating point calculations in hardware. To get larger floating
point values you would have to use a software library, which would be
enormously slower.

Besides, 0.1 is inaccurate in binary floating point format regardless
of the number of bits used (for the exact same reason as 1/3 is
inaccurate in decimal format regardless of how many decimals you use).

> Like 8,000 bits or 8,000,000 bits or any number of bits necessary to
> store all the possible numbers for double for example.


double already stores all possible numbers representable with a double.
 
Reply With Quote
 
Michael.Boehnisch@gmail.com
Guest
Posts: n/a
 
      04-10-2008
On 10 Apr., 01:49, Ioannis Vranos <(E-Mail Removed)>
wrote:
> (E-Mail Removed) wrote:
> > Machine double numbers are a finite subset of the
> > infinite real number domain. The operations on them executed by a
> > computer are similar but not identical to the math +, -, *, /, ...
> > operators 0.1 + 0.1 + 0.1 + 0.1 + 0.1 .


oops. " != 0.5 " is missing.

>
> Then why doesn't an implementation use a large number of bits, for
> people that want accuracy and also for x==y to work?
>
> Like 8,000 bits or 8,000,000 bits or any number of bits necessary to
> store all the possible numbers for double for example.


A large number of bits is not enough, you'd need an *inifinte* number
of bits. Even if you extend the "normal" double numbers concept by
fractions (e.g. store two integer numbers 1 and 10 to represent 1/10),
you cannot represent the whole rational set (e.g. sqrt(2), pi or e
cannot be stored like this without loss of precision). Also, there is
an issue in performance: the more memory you use to store a single
value, the longer it will take to operate on them.

AFAIR, the current implementation by x86 CPUs uses 80 binary digits
for an extended precision floating point number internally and 64
binary digits to store a double in RAM memory. Should be enough for
most applications, *if* you follow the caveats mentioned before. -
Especially do not compare floats/doubles for (in)equality by != / ==
operators. If you want more precision you need to do it by application
code. This is considerably slower than using direct CPU/FPU commands
for floating point.

best,
Michael.
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      04-10-2008
On Apr 10, 1:49 am, Ioannis Vranos <(E-Mail Removed)>
wrote:
> (E-Mail Removed) wrote:
> > Machine double numbers are a finite subset of the
> > infinite real number domain. The operations on them executed by a
> > computer are similar but not identical to the math +, -, *, /, ...
> > operators 0.1 + 0.1 + 0.1 + 0.1 + 0.1 .


> Then why doesn't an implementation use a large number of bits, for
> people that want accuracy and also for x==y to work?


> Like 8,000 bits or 8,000,000 bits or any number of bits
> necessary to store all the possible numbers for double for
> example.


I'm not sure I understand. A double has enough bits to store
all possible numbers for double. By definition---if the number
can't be stored in a double, then it's not a possible number for
double.

The problem here is that the real number 0.1 is not a possible
number for double. And if you're asking that the implementation
use enough bits to store all possible real numbers, that's
lg2(N), where N is the number of possible real numbers. And off
hand, how many possible real numbers would you say there are?

In this particular case, an implementation could have masked the
problem by using a decimal representation for double. But that
will fail as soon as you try something like:

step = 1.0/3.0 ;
for ( value = 0.0 ; value != 1.0 ; value += step ) ...

(Back when I was working in this environment, I actually wrote a
proof that for all finite representations of floating point
values, the loop:

step = 1.0/N ;
for ( value = 0.0 ; value != 1.0 ; value += step )

will fail for some values of N.)

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Triple nested loop python (While loop insde of for loop inside ofwhile loop) Isaac Won Python 9 03-04-2013 10:08 AM
comparing field data from previous field in loop with null values abbylee26@hotmail.com ASP General 6 02-15-2006 01:59 PM
cannot convert parameter from 'double (double)' to 'double (__cdecl *)(double)' error Sydex C++ 12 02-17-2005 06:30 PM
Wrong results when comparing negative double variables in an if statement John C Programming 11 05-05-2004 04:06 PM
Problem comparing a double with 0 =?iso-8859-1?Q?Juli=E1n?= Albo C++ 2 07-02-2003 06:05 PM



Advertisments