double variable question

P

polymedes

Can some body explain to me this:

Consider the following code:

int main(int argc, char* argv[]) {
double d1;

d1 = 11.0;
d1 -= 1.8;
d1 -= 3.0; //HERE THE DEBBUGER SHOWS 6.1999999999999993 !!!

printf("%f", d1); //THE OUTPUT IS 6.200000 (ok, we have less digits)
getch();

return 0;
}

I don't understand it. Is it the debuger shows me wrong data, or
something i don't know?
 
M

Michael Mair

polymedes said:
Can some body explain to me this:

Consider the following code:

int main(int argc, char* argv[]) {
double d1;

d1 = 11.0;
d1 -= 1.8;
d1 -= 3.0; //HERE THE DEBBUGER SHOWS 6.1999999999999993 !!!

printf("%f", d1); //THE OUTPUT IS 6.200000 (ok, we have less digits)
getch();

return 0;
}

I don't understand it. Is it the debuger shows me wrong data, or
something i don't know?

The debugger shows you the decimal representation of the binary fraction
stored in the double. If you ask for full precision when using printf(),
you will get the same result.

6.2 is 6+1.0/5, 1.0/5 has no finite representation as binary fraction,
thus you get only an approximation of it. The decimal representation of
0.2 is only finite because 5 is a product of the prime numbers building
up the base 10 (namely, 2 and 5). So, 1.0/(5*5*2) has a finite
representation, but 1.0/3 or 1.0/7 etc has not.

In order to understand the issues at hand better, I suggest some heavy
reading:

http://docs.sun.com/source/806-3568/ncg_goldberg.html

The first sections should be enough for a start :)


Cheers
Michael
 
D

dandelion

polymedes said:
Can some body explain to me this:

Consider the following code:

int main(int argc, char* argv[]) {
double d1;

d1 = 11.0;
d1 -= 1.8;
d1 -= 3.0; //HERE THE DEBBUGER SHOWS 6.1999999999999993 !!!

printf("%f", d1); //THE OUTPUT IS 6.200000 (ok, we have less digits)
getch();

return 0;
}

I don't understand it. Is it the debuger shows me wrong data, or
something i don't know?

Probably the latter.

Floating point numbers (float, double) are not the same as mathematical Real
numbers. Mor specifically, they have a limited precision.

Usually they are represented as mantissa*2^exponent (instead
ofmantissa*10^exponent). Now if a certain figure (say 6.2) cannot be
represented that way, the result will be the nearest *) number that can. In
this case 6.1999999999999993. Now it may look dramatic in your debugger, but
the difference is actually very small.

If you are writing programs using floats or doubles, you should take this
into account. For instance,
comparing two floating point numbers for equality using a blunt "=="
operator is (usually) not a good idea, for the reasons stated above.
Instead, check wether the absolute difference between the two
numbers is less than a specific limit (usually called epsilon).

So nothing bad is happening in your program.

*) Not sure, could be rounded up/down and be implementations specific.
 
P

polymedes

Michael said:
polymedes said:
Can some body explain to me this:

Consider the following code:

int main(int argc, char* argv[]) {
double d1;

d1 = 11.0;
d1 -= 1.8;
d1 -= 3.0; //HERE THE DEBBUGER SHOWS 6.1999999999999993 !!!

printf("%f", d1); //THE OUTPUT IS 6.200000 (ok, we have less digits)
getch();

return 0;
}

I don't understand it. Is it the debuger shows me wrong data, or
something i don't know?


The debugger shows you the decimal representation of the binary fraction
stored in the double. If you ask for full precision when using printf(),
you will get the same result.

6.2 is 6+1.0/5, 1.0/5 has no finite representation as binary fraction,
thus you get only an approximation of it. The decimal representation of
0.2 is only finite because 5 is a product of the prime numbers building
up the base 10 (namely, 2 and 5). So, 1.0/(5*5*2) has a finite
representation, but 1.0/3 or 1.0/7 etc has not.

In order to understand the issues at hand better, I suggest some heavy
reading:

http://docs.sun.com/source/806-3568/ncg_goldberg.html

The first sections should be enough for a start :)


Cheers
Michael

Thanks a lot Michael. This is really interesting.
 
M

Martin Ambuhl

polymedes said:
Can some body explain to me this:

Consider the following code:

int main(int argc, char* argv[]) {
double d1;

d1 = 11.0;
d1 -= 1.8;
d1 -= 3.0; //HERE THE DEBBUGER SHOWS 6.1999999999999993 !!!

printf("%f", d1); //THE OUTPUT IS 6.200000 (ok, we have less digits)
getch();

return 0;
}

I don't understand it. Is it the debuger shows me wrong data, or
something i don't know?

This is the output of a tiny program I just wrote. I am not including
the program, since it would be useful and easy for you to write one for
yourself, just as checking the FAQ before posting is easy. Look
carefully at the output (if you prefer hex, make your program output hex):

On this implementation,
FLT_DIG = 6, FLT_MANT_DIG=24
DBL_DIG = 15, DBL_MANT_DIG=53
LDBL_DIG = 18, LDBL_MANT_DIG=64

Showing 6.2f (float) as octal:
6.1463146
Showing 6.1999999999999993f (float) as octal:
6.1463146

Showing 6.2 (double) as octal:
6.14631463146314632
Showing 6.1999999999999993 (double) as octal:
6.1463146314631463

Showing 6.2L (long double) as octal:
6.14631463146314631463
Showing 6.1999999999999993L (long double) as octal:
6.14631463146314630014
 
G

Gordon Burditt

Consider the following code:
int main(int argc, char* argv[]) {
double d1;

d1 = 11.0;
d1 -= 1.8;
d1 -= 3.0; //HERE THE DEBBUGER SHOWS 6.1999999999999993 !!!

printf("%f", d1); //THE OUTPUT IS 6.200000 (ok, we have less digits)
getch();

return 0;
}

I don't understand it. Is it the debuger shows me wrong data, or
something i don't know?

There is no exact value of 6.2 in binary floating point (nor of
1.8). 0.1 is an infinite repeating decimal in binary. Also,
floating point operations are subject to round-off error.
For example, (1 + 100000000000000000000) - 100000000000000000000 has
a darn good chance of coming out zero.

If it's not an exact integer, and it doesn't end in 5 (with trailing
0's removed) it doesn't have an exact representation in binary
floating point.

If it's not an exact integer, has at least two decimal places, and
it doesn't end in 25 or 75 (with trailing 0's removed), it doesn't
have an exact representation in binary floating point.

If it's not an exact integer, has at least three decimal places,
and it doesn't end in 125, 375, 625, or 875 (with trailing 0's
removed), it doesn't have an exact representation in binary floating
point.

It appears that the double value you printed had roundoff error of 1 in the
least significant bit, making it match the 'before' value below:

6.2 as double:
Before: 6.199999999999999289457264239899814128875732421875000000000000
Value: 6.200000000000000177635683940025046467781066894531250000000000
After: 6.200000000000001065814103640150278806686401367187500000000000

6.2 as float:
Before: 6.199999332427978515625000000000000000000000000000000000000000
Value: 6.199999809265136718750000000000000000000000000000000000000000
After: 6.200000286102294921875000000000000000000000000000000000000000

For IEEE doubles, which I suspect you are using, DBL_DIG is 15, and the printed
result is 1 off in the 16th place, so you have nothing to complain about.

Gordon L. Burditt
 
K

Keith Thompson

polymedes said:
Can some body explain to me this:

Consider the following code:

int main(int argc, char* argv[]) {
double d1;

d1 = 11.0;
d1 -= 1.8;
d1 -= 3.0; //HERE THE DEBBUGER SHOWS 6.1999999999999993 !!!

printf("%f", d1); //THE OUTPUT IS 6.200000 (ok, we have less digits)
getch();

return 0;
}

The C FAQ is at <http://www.eskimo.com/~scs/C-faq/top.html>. Read
question 14.1. Then read the rest of section 14. Then read the whole
thing.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,157
Messages
2,570,879
Members
47,413
Latest member
KeiraLight

Latest Threads

Top