Sign in to follow this  
mike74

strange rounding

Recommended Posts

I have the following code: cout << int((log(8)/log(2))) << endl; float somefloat = log(8)/log(2); cout << int(somefloat) << endl; Anyone know why it prints out two different numbers? mike http://www.coolgroups.com/

Share this post


Link to post
Share on other sites
In my opinion log(8)/log(2) = 3 [smile]

The problem can be related to the fact that log(8)/log(2) is something equal 3 minus a little tollerance caused by float precision so when you cast to int
( int i = (int)f ) you cut the mantissa and you get 2 instead of 3.

Share this post


Link to post
Share on other sites
What values does it actually give?

The best explanation I can think of is that in the 1st case because the result is cast to an integer it uses the default log function which returns a double, but in the second case it uses the logf function which returns float. That would cost you precision which might cause it to round differently. That seems to be odd behaviour and I don't know if it's standard or not. What compiler are you using? You can always check the assembler code produced and see what the difference is.

Share this post


Link to post
Share on other sites
It prints:

2
3

Also, I'm using Dev-cpp. Please try it out and let me know if you get the same results.

mike
http://www.coolgroups.com/

Share this post


Link to post
Share on other sites
In the first case you're casting double to int, a double which is slightly less than 3, giving the result of 2.
In the second case you're implicitly casting (compiler should warn you) from double to float in assigning to 'somefloat', in which the rounding will give the float a value of 3. So when you come to cast from the float to int, it'll be 3.

Share this post


Link to post
Share on other sites
If this was true, then why does the following print 3?

double somedouble = log(8)/log(2);
cout << int(somedouble) << endl;


Quote:
Original post by c2_0
In the first case you're casting double to int, a double which is slightly less than 3, giving the result of 2.
In the second case you're implicitly casting (compiler should warn you) from double to float in assigning to 'somefloat', in which the rounding will give the float a value of 3. So when you come to cast from the float to int, it'll be 3.


Share this post


Link to post
Share on other sites
It's possible that one case is pulling the result off the FPU stack as a double before converting it to float, whereas the other case is pulling it off as a float in the first place.

It doesn't really matter, though. The bottom line is, you're converting a float to an int, and it's giving you problems. That's what happens when you count on floating-point numbers to be exact. Lesson learned: from now on, if you need to go from a float to an int, round it instead of truncating it.

Share this post


Link to post
Share on other sites
Internally it would be using extended precision (80bits - long double).

When you assign to the double, that internal result will get rounded to 3.

So, I'll correct myself. It would be the conversion from the extended precision to either double or float which rounds to 3, not the conversion from double to float (although, the principle is the same ... there's a very small rounding error in the calculations which gets discarded when rounding to a less precise format. This is also the reason for keeping internal calculation at higher precision than the representation in memory)

--EDIT--
And, like Sneftel said, round instead of cast.

Share this post


Link to post
Share on other sites
It looks like you're right. When I do:

long double somedouble = log(8)/log(2);
cout << int(somedouble) << endl;

It produces the incorrect 2.

Quote:
Original post by c2_0
Internally it would be using extended precision (80bits - long double).

When you assign to the double, that internal result will get rounded to 3.

So, I'll correct myself. It would be the conversion from the extended precision to either double or float which rounds to 3, not the conversion from double to float (although, the principle is the same ... there's a very small rounding error in the calculations which gets discarded when rounding to a less precise format. This is also the reason for keeping internal calculation at higher precision than the representation in memory)

--EDIT--
And, like Sneftel said, round instead of cast.


Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this