• Advertisement
Sign in to follow this  

Wierd bug with casting floats - int and floor()

This topic is 4498 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Had a wierd bug I fixed today, and while I am confident my solution fixed it, I'm still not 100% sure on why it was breaking. Basically, the code was basically this:
void foo(int x) {
  ...

  if( x != floor(x) ) {
    ... // bad
  } else {
    ... // good
  }

  ...
}


The code was left in from when x was a double and not an int. The original use was to test that the value being passed was not a decimal number, ie have a .01051 or something. So it worked by comparing the value passed in to the floor of that value, to check that it was valid (in this case it was necessary because the double was being cast as a pointer to a buffer of memory). So, here is the wierd thing. In VS6 this was never a problem, and the test always passed into the good section. In VS2003 however, on some machines we could cause it to fall into the bad section, even though a valid pointer was being passed in. On some machines it always worked as it should, on others it would sometimes work sometimes not, dependant on if it was a release or debug build of the code. I fixed the problem by just removing that code, but still don't understand fully what was breaking it. The only thing I can gather so far, is that the x might of been interpreted as a negative number in some cases. Since it was signed, anything over 0x80000000 would be negative. Thus, if the address existed in that memory space, it would be interpreted as a negative number, ie -3153 which would be converted to a float, -3153.0000. However, if I'm not mistaken (I could very well be, been a while since my scientific computing class) the float is just an approximation, so it likely doesn't end in .0000 but more like -3153.000134 or something. Then, the floor function on negative numbers would not return -3153, but -3154. Then comparing the -3154 to the original value of -3153 would trip it into the bad section. That seemed to be a plausable explanation. However, the values being passed in didn't really support that. For instance, the address 0x04B9C0DC would trip into the bad section, while 0x00ACA9B8 wouldn't. That got me kind of confused. Is there something going on with the way things are being cast? It could just be that the values I was getting for the value of x were off, because the machines that would put the code into the bad section didn't have any debug tools, so I kind of had to hack out some loging stuff that might not of been perfect.

Share this post


Link to post
Share on other sites
Advertisement
All (32-bit) ints can be represented exactly as doubles, but not as floats. Are ints automatically promoted to floats or doubles in C++?

If floor is applied to floats I would expect most ints > 2^24 to take the "wrong"-path.

Share this post


Link to post
Share on other sites
Isn't it generally not advised to check equality for floating point numbers? But then, it's not advised to totally confuse whoever maintains the code either, even if it's you.

Share this post


Link to post
Share on other sites
Quote:
Original post by Trap
All (32-bit) ints can be represented exactly as doubles, but not as floats. Are ints automatically promoted to floats or doubles in C++?
Doubles.
My guess is that someone (Direct3D..) has reconfigured the x87's precision and thus effectively gotten it truncated to a 32-bit float anyway.

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
why arent you passing in a pointer directly?

why all the witchery?


Well the code wasn't originally mine, but basically it was a generic function that would be called to set up tasks. The kinds of tasks and data they required had a number of different kinds and numbers of parameters and values. Rather than using function overloading, or something else, the original author just made it very generic so that a single function could be used for everything. Really it was kind of slick in the end and worked fine for C/C++.

Share this post


Link to post
Share on other sites
Quote:
Original post by Trap
All (32-bit) ints can be represented exactly as doubles, but not as floats. Are ints automatically promoted to floats or doubles in C++?

If floor is applied to floats I would expect most ints > 2^24 to take the "wrong"-path.


The floor() function has three overloads.

One that takes and returns a float, one that takes and returns a double, and one that takes and returns a long double. It's casting the int to one of those since there is no int version of the function. I can't say in the VC6 code, because it was somehow picking which to use. In the vs2003 code, the compiler threw an error saying it didn't know which to use (which makes sense) so I had to cast them all explicitly as a float.

Share this post


Link to post
Share on other sites
Quote:
Original post by DrjonesDW3d
In the vs2003 code, the compiler threw an error saying it didn't know which to use (which makes sense) so I had to cast them all explicitly as a float.

So this bug is your fault. Learn from it.

Share this post


Link to post
Share on other sites
Quote:
Original post by Trap
Quote:
Original post by DrjonesDW3d
In the vs2003 code, the compiler threw an error saying it didn't know which to use (which makes sense) so I had to cast them all explicitly as a float.

So this bug is your fault. Learn from it.


Yea, and come to think of it I don't even remember why I chose float instead of double. However, it was kind of good that we 'caused the problem, because it was just messy code that really didn't do anything as was unneeded. Without it breaking anything I probably wouldn't of ever bothered looking at it or wondering what it did.

Now as a result, the code is cleaner, and I learned to be extra careful about float <-> int conversions.

Also learned that the guy who originally wrote it (who is an AMAZING programmer) didn't write perfect code and so not to assume that everything he does was done right or needed to be done. I picked up some remote debugging skills while I was at it too.

My main reason for making this thread was to try and fully understand what was in fact causing the bug (even though it's fixed), since all the thinking I did on the matter didn't convince me.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement