# Thread: efficiency comparing ints and floats

1. ## efficiency comparing ints and floats

I guess this is a laziness question about how many times I have to type ".0". If I'm comparing a floating point variable to an integer value, like:
Code:
`if (Rotation==360)`
will the processor end up having to perform some additional conversion to do the comparison?, as opposed to
Code:
`if (Rotation==360.0)`
or can I just expect the compiler is smarter than that?

2. Rule 1 - don't compare for equality
http://c-faq.com/fp/fpequal.html

Why are YOU concerned with such microscopic optimisations?

Look at the ASM

3. This raises another question, naturally (and thanks for that tip). I presume it only applies if the float is the product of some operation which could give it any number of decimal places? In reality, this number
Code:
`if (Rotation==360)`
is always an integer because the only thing that ever happens to it is it gets incremented or decremented by 1. It's a float because it's used by a function that expects a float and this seems easier than casting it (is that a mistake?) Anyway, the comparison should be okay then, right?

As for the "micro-optimization", well it just occurred to me that by not bothering to add the .0 I might just as well (for all I know) throw in some extra trig functions or something (for no good reason), which means all my fine algorithmic thinking will be wasted.

But no, I won't look at the ASM. I never look at the ASM. Where is the ASM?

4. Look at the ASM
Exactly.

It appears that the following code compiles into exactly the same thing whether you have 360.0 or 360:

Code:
```int main(void)
{
double d = 1.0;
if (d == 360) {
d = 0.0;
}
return 0;
}```
I don't see any reason why the compiler shouldn't realize that the literal 360 is compared against a double and therefore replace it with 360.0 for you.

Rule 1 - don't compare for equality
But what if all the calculations I do with the float only involve operations and values that can be represented precisely? (E.g, if I know I will be only adding or subtracting 0.25, 0.5 or 0.75 from small values.)

Where is the ASM?
I think it is the thing that you get when you do:

Code:
`gcc a.c -S -o a.txt`

5. > But what if all the calculations I do with the float only involve operations and values that can be represented precisely?
I think it would be a dangerous habit to get used to.

Sure it might work for a while, but then you'll use it for something you shouldn't, and won't remember the reasons why it was OK in the special case.

6. Originally Posted by anon
But what if all the calculations I do with the float only involve operations and values that can be represented precisely?
That's what I'm asking in the last post (when I said "is always an integer", I meant an integer, not a C int). You could check this one by printing all the bits out, I think, but I won't bother doing that either. I'm sure if the number has a fixed precision it will be okay.

Oh -- and thank you oh so much (!!) for finding that assembly code for me...

7. Originally Posted by MK27
That's what I'm asking in the last post (when I said "is always an integer", I meant an integer, not a C int). You could check this one by printing all the bits out, I think, but I won't bother doing that either. I'm sure if the number has a fixed precision it will be okay.

Oh -- and thank you oh so much (!!) for finding that assembly code for me...
So you actually know what formats can exactly be represented exactly by floating point values? Wow.
Because I don't. I don't even think the standard does - I'm pretty sure it doesn't. Since it's implementation defined.

On most implementations, however, I can tell you even the simple number "0.1" can't be represented exactly. Surprised? Then don't use exact float comparison in any situation. Not surprised? Then still don't use exact float comparison in any situation.

Sorry, but the entire fact you say you 'know' that comparing exactly is legal in your case makes me think that you don't know enough about all of this to know whether it's legal.

8. So you actually know what formats can exactly be represented exactly by floating point values? Wow.
Because I don't. I don't even think the standard does - I'm pretty sure it doesn't. Since it's implementation defined.
No expert here but from the IEzzz standard or whatever it is called, which seems to be rather universally used (except perhaps for strange and exceptional architectures) it should follow that integers in a certain range (I think a lot larger than 32-bit int for doubles) as well as fractional values that are (negative) powers of two and their sums up to some precision can be represented precicely: e.g 0.5, 0.25, 0.75, 0.125, 0.625 etc. Not all floating point values are approximations.

0.1, though, cannot indeed be represented precisely in this standard.

It would seem to me that as long as you can guarantee that your float values indeed hold integral values (no calculations that would violate that, e.g you know that all operations are additions or substractions in a relatively small range), you might be quite safe with such comparisons.

So the question is, whether you should use integers and cast them to floats as the API requires, or use floats to begin with - even though you only want them to store integral values. I guess there is no single answer - it would largely depend on what you do with the variables, how often you pass them to functions etc. Only way to know is to try it both ways and profile the performance in either case. (You can use a typedef that can be either float or int and use that for all such variables - assuming your program is correct in the first place with floats - e.g no integer division: then trying both ways might mean changing just one line and recompiling.)

I wouldn't be rather surprised if you find that this doesn't matter. If a program feels slow, either it simply has to do so much work that any micro-optimization won't make any noticeable difference (there's no difference between waiting 4950 or 5000 ms for an operation to complete), or you can make a large-scale optimization (use a better algorithm/data representation scheme - and that's not just variable types) bringing the time of the operation perhaps down to 2500 or even 500 ms or less and really making a discernible difference.

If you use an algorithm with bad complexity and I know a better algorithm then you can micro-optimize all you want, your C program is not going to beat my Python program (which might be about 30 times slower than C at raw number crunching - tested with determining primeness with the same algorithm) for sufficiently large input.

I also believe there is not much point in creating a small test program and testing the efficiency of a single operation by itself. While you may see that one way is 200% faster than the other, in a real program and with real workload this particular operation may be taking 0.01% of total execution time, so reducing that 200% wouldn't make much of a difference.

9. Thanks for reminding me of this important point about doing math with fixed precision numbers in C, gang.

10. Also, if you are worried about micro-optimizations, then you are doing something else wrong, as well.
if (x == 10.0)
If x is a float, then x will be promoted to a double, and then compared. Oops.
Learn to distinguish floats and doubles!
if (x == 10.0f)

11. Originally Posted by Elysia
If x is a float, then x will be promoted to a double, and then compared. Oops.
Learn to distinguish floats and doubles!
if (x == 10.0f)
Did not know that! Thanks again Elysia!

12. Originally Posted by EVOEx
So you actually know what formats can exactly be represented exactly by floating point values? Wow.
Because I don't. I don't even think the standard does - I'm pretty sure it doesn't. Since it's implementation defined.

On most implementations, however, I can tell you even the simple number "0.1" can't be represented exactly. Surprised? Then don't use exact float comparison in any situation. Not surprised? Then still don't use exact float comparison in any situation.

Sorry, but the entire fact you say you 'know' that comparing exactly is legal in your case makes me think that you don't know enough about all of this to know whether it's legal.
It is possible to know what values on a particular platform can be represented exactly. Seeing as how I've written my own mega floating point class before that is stored and works identically to float on an x86 CPU, I'm pretty confident that I know what can and cant be represented.
As for MK27, I'm not sure.
Anyway, the issue here applies regardless of whether there is an exact float comparison going on. He could have written Rotation < 360. The answer should be that it makes no diference whether it is written as 360, 360.f, or 360.0, it's about as easy for a compiler to work out which is best at compile time, as adding 1+1 is. Just write whatever you like.

13. Originally Posted by iMalc
It is possible to know what values on a particular platform can be represented exactly. Seeing as how I've written my own mega floating point class before that is stored and works identically to float on an x86 CPU, I'm pretty confident that I know what can and cant be represented.
As for MK27, I'm not sure.
Anyway, the issue here applies regardless of whether there is an exact float comparison going on. He could have written Rotation < 360. The answer should be that it makes no diference whether it is written as 360, 360.f, or 360.0, it's about as easy for a compiler to work out which is best at compile time, as adding 1+1 is. Just write whatever you like.
However, to avoid simple compilers doing the wrong thing, using 360.0f or 360.0 depending on whether rotation is a double or float will not HURT. It is at the most three characters more, and almost certain to NEVER be worse than what the compiler comes up with. Bear in mind tho', that if you DO change rotation to be an integer, then 360.0 WILL mean that the compiler converts the integer value to a double, which is never a good plan.

Also, do not be tempted to try to make it faster with:
Code:
`if ((int)rotation == 360)`
It is valid converting a float to integer this way, and if that's what you really want, fine. However, it is absolutely certainly not faster (at least not on hardware that has floating point operations), since converting float to integer is slower than comparing a constant float with another float value.

--
Mats

14. Originally Posted by EVOEx
So you actually know what formats can exactly be represented exactly by floating point values? Wow.
Because I don't. I don't even think the standard does - I'm pretty sure it doesn't. Since it's implementation defined.
Any floating point implementation that can't represent integral values exactly is broken. You would have to deliberately go out of your way to design an implementation where this was not the case, and I can't imagine any benefit from doing so.

If the value is always an integer, then I question the use of a floating point type to store it, but I would not worry about the equality check. It's kind of unclear, though.

EDIT: I would assume that the comparison in question is part of some code that looks like this:

Code:
```if(rotation == 360)
{
// make sure angle stays between 0 and 360
rotation = 0;
}```
But I would never write it that way -- I'd do this:

Code:
```if(rotation >= 360.0)
{
rotation -= 360.0;
}```

15. Obviously, very LARGE integer values can not be represented exactly (the last digits turn to zeros, generally), but I do agree that integer values in the range that is represented in the mantiass (that is, for float 2^23 or so, and 2^53 or so for double) should be possible to represent precisely.

That in itself doesn't mean that you can't get inprecise values even if the value itself can be represented exactly. Whenever you use add or subtract on floating point values, both numbers need to be "the same exponent". So if you have a very large number, and try to add/subtract a very small number, the small number will first be multiplied up to match the large number. Of course, this means that if you then subtract the large number again, some of the smaller parts may have gone missing in the processing.

--
Mats