int s = (.7 * 3) + (.3 * 3) is 2 ?

Started by
60 comments, last by Zahlman 19 years, 9 months ago
int main(){  int a=3;  float b=.7f*3+0.3f*3;  double c=.7*3+0.3*3;  printf("%i %i %i\n",a,(int)b,(int)c);  printf("%i %.30f %.30f\n",a,b,c);}


gives
3 3 2
3 3.000000000000000000000000000000 2.999999999999999555910790149937

which is exactly what MaulingMonkey said
Advertisement
Quote:Original post by civguy
Quote:Original post by Eelco
the problem is flats cant really take most values. a float can be exactly 1, exactly 2, but not exactly 3, for example.
Floats can be exactly 3 as well. Floats can represent all whole numbers exactly as long as the number is small enough to fit in the mantissa.


yeah youre right.

my tests show that 2.1 + 0.9 (making sure the compiler cant add them at compiletime) does exactly yield the same bitpattern as a constant float with value 3. it cant be an inaccuracy in the adding, so it must be a rounding quirck then.
@keen

I copied your code as written and compiled it, and my results were:

3 3 2
3 3.000000000000000000000000000000 2.999999999999999600000000000000

Does it depend on the fpu, compiler, sdks, OS, etc?
Why would mine display different results?

- prowst
Quote:Original post by prowst
Quote:
Nothing is 'exactly' in floating point math. If you want to write 0.9 exacly in FP mathy you need 'exactly' infinite digits


I dont understand why this is the case for rational numbers.
If it was an irrational number, then I see why you would need
"exactly infinite digits".

- prowst

Rational means that a number can be expressed as the ratio of two whole numbers, but that's simply not how computers store numbers. Rational numbers can also have infinitely-repeating digits in decimal (e.g. 1/3; rational but takes an infinite number of digits in base-10 to express).

.9 can be represented as a single-digit number in a decimal numbering system where each digit is the coefficient of the place:
...00.900...
= ...0*10^1 + 0*10^0 + 9*10^-1 + 0*10^-2 + 0*10^-3...
= ...0*10 + 0*1 + 9*.1 + 0*.01 + 0*.001...
You can represent any number in decimal without repeating digits if it can be expressed a sum of powers of 10.

Since computers store numbers in binary, you're only going to have a finite number of non-zero digits if it exactly fits with the binary coefficients:
...ab.cd...
= ...a*2^1 + b*2^0 + c*2^-1 + d*2^-2...
= ...a*2 + b*1 + c*.5 + d*.25

Where the coefficients are either 0 or 1. Try working out .9 and you'll find you go on forever.

In summation, you can only represent a number in floating point exactly if it can be represented as a sum of powers of two. .9 is not such a number, but all whole numbers are.
Quote:Original post by MichaelT
Quote:Original post by MaulingMonkey
WRONG order of operations for his statement, sorry.


Handling them like that works just as well for that particular problem.


In your exmaple you're implying a different order of operations than is occuring, by using his equasion and then suddenly going off on a tangent doing your own thing instead of the same thing as the main equasion.

It does NOT work "just as well" as it fails to explain how a compiler determines this case usually. It has potential to confuse any newbies who read the topic, which is the reason I'm now quite annoyed that you appear to be trying to defend your example.
Quote:Original post by prowst
@keen

I copied your code as written and compiled it, and my results were:

3 3 2
3 3.000000000000000000000000000000 2.999999999999999600000000000000

Does it depend on the fpu, compiler, sdks, OS, etc?
Why would mine display different results?

- prowst


Your compiler is probably generating slightly different instructions.
Quote:Original post by MichaelT
the code is wrong. A double only have 10 digits of precision not 30. A float have 6 digits of precision (FYI)
Correct them to 6 and 10 and you will find both to be 3.00... The undefined behaviour comes when you try and go beyond the limitations of the types.


The code is not "wrong". Floats and doubles are in binary, and do not exacly correspond to the decimal system. Correcting them both to "6 and 10" will merely round the numbers off in an printf-implementation-dependant way.
Quote:Original post by MichaelT
or: 0.7 + 0.7 + 0.7 = 2.1 (all doubles)

This will easily fit inside a float but that is irrelevant since
this is a double.

No, it won't. It is impossible to represent 2.1 exactly in a float or a double.
Quote:Original post by MichaelT
Quote:Original post by sjelkjd
No, it won't. It is impossible to represent 2.1 exactly in a float or a double.


For all intents and purposes it is exact


NO NO NO for all intents and purpouses it is NOT EXACT as UNDERLINED by the problem that an apparent 3.0 is rounded down to 2 when converted to an int as was the original topic problem!!!

Quote:Original post by MichaelT

It is wrong, you are trying to use more precision than the type can handle and as a result you get junk values.


Wrong, it is generating what it percieves to be the closest value to the floating point representation. The actual value of the floating point does not come down to a nice packaged number that necessairly has a finite number of decimal points. Each extra shown digit is not a "junk value" but rather a closer approximation to the actual floating point number.

Quote:Yes it will round off but only where there is no more room in the type(You cannot fill a box more than it can hold) Printf has nothing to do with it, it is the types. Check your programmers reference and look up the definition of the types.


What the hell are you babbling <_<;;. It will round, period. It has nothing to do with room in "the type", only room in "the number of digits I have specifically limited printf to displaying".


Quote:You are trying to add way more complexity into a problem than it deserves.


I'm trying to keep you from obfuscating things.

Quote:I can't do anything about you not accepting that the computer does have limitations.


I don't see what I'm not "accepting".

Quote:You need to work within those limitations but by typecasting a value that is way beyond its limits you are inviting trouble.


"way beyond it's limits"... we're talking about 3 here!!! not 10 to the 1000th power, with the loss of precision meaning that our numbers are off by over a hundred in all probability... we're talking about "3" getting rounded down to 2.

Quote:You need to start accepting that there are real hardware limits here and work with them not against them.


I am quite aware that there are hardware limits. What you need to accept is that your example is misleading, that floating points arn't exact for all intents and purpouses, and the "digits of precision" refer to the minimal incrementable unit of a floating point, not how many digits that floating point actually reducable into.
Quote:Original post by MaulingMonkey

....



#include <math.h>

int _tmain(int argc, _TCHAR* argv[])
{
double a = 3.0;

int c = ceil((0.7 * a) + (0.3 * a));

printf("%i",c);

return 0;
}
No no no no! :)

This topic is closed to new replies.

Advertisement