Game Development Community

Float-values not equaling properly??

by Drew -Gaiiden- Sikora · in Torque Game Builder · 12/15/2006 (11:30 pm) · 8 replies

I've come across a weird... bug? I'm not sure so before I post about it in the Bugs forum I want to try here first. Here is the code in question
echo($pref::Audio::channelVolume2);
if ($pref::Audio::channelVolume2 < 0.9)
   echo("true!");
here is the console output
0.9
True!
How is this possible?? Hazel mentioned in #tgb that maybe the value of $pref::Audio::channelVolume2 is actually 0.89999 or something, but I can't see then why echo() would spit out 0.9.

So I was like "okay, that's weird" and decided to try doing it another way
echo($pref::Audio::channelVolume2);
if ($pref::Audio::channelVolume2 <= 0.8)
   echo("true!");
Again, it failed - as evidenced by the console output
0.9
0.8 <= should have been true after this!
0.7
True!
Can anyone explain this? I'm at a loss here. Thanks in advance!!

#1
12/17/2006 (5:59 pm)
It is pretty much standard in programming that you shouldn't be doing equality comparisons against floats. The printed representation may not reflect the actual float down to all 32 bits. If you must do this, you'll want something like:

if ( (%x + 0.01 < 0.9) || (%x - 0.01 > 0.9)) {
//code to run if %x isn't within 0.01 of 0.9
} else {
//code to run if %x is within 0.01 of 0.9
}

Or wrap that up and put it into a function for easier comparisons.

In general, if you need exact numbers, often you don't need a float. I've had to write that sort of function for a few programs but not many.


In your case, if the volume has 10 different settings, don't use <= for comparisons, just use < and compare it to something like .82.

if ($pref::Audio::channelVolume2 <= 0.82)
echo("true!");
#2
12/18/2006 (1:55 am)
Another good way to compare floats is to get the difference and check for a difference.

%valOne = 0.9;
%valTwo = 0.899;

%diff = mAbs(%valOne - %valTwo)

if(%diff <= 0.01)
{

}
#3
12/18/2006 (2:06 am)
Thx guys. I try to use floats as little as possible, so it's no wonder I didn't know about the accuracy issue. Or, I prob just plain forgot that part of my CS courses back in school. Not that I really paid that much attention anyways :P
#4
12/18/2006 (3:51 am)
Hi. Sorry to hop in. Do I understand this right? A comparison of

%diff = 0.8;

if (%diff < 0.9)
{
...

will return false, but this one with a trailing 0 behind the .9 will return true?

if (%diff < 0.9[b]0[/b])
{
...

I always thought that float comparisons in TorqueScript are safe to use.

Martin
#5
12/18/2006 (7:06 am)
@Martin - no. 0.8 will be less than 0.90 or 0.9

He comparing two 0.8's derived from different sources can have undefined results, however. It would be less than, greater than or equal.


I do want to add a bit to what I said about normally using integers. This looks like you're setting volume and you have the normal settings 0.0 to 1.0. I'd suggest using integers with respect to the GUI. Have settings from zero to 10. Instead of a continuous bar, you have 10 discrete points on that bar. Only at the last moment before you set the sound volume in the code would you change it to a float. Then you could do equality comparisons directly.

Well, that may or may not be what you want in this situation but that's the idea. If you want discrete points use integers until the very last moment. Also doing this, you'd never check the game volume directly. You'd only set it from the stored values.
#6
12/18/2006 (7:15 am)
Ah, thanks, got it.
#7
12/18/2006 (5:38 pm)
Thx guys. Yea Lance, I'll just use whole-number conversion.

I just want to also mention that you can directly compare floats, but only for direct comparisons, because then you can use the $= operator
if ($pref::Audio::channelVolume2 $= 0.9)
   butSfxVolumeUp.setActive(false);
This has worked without fail for me
#8
01/27/2007 (3:12 am)
Even though this is an old thread, I thought I'd explain *why* you shouldn't do equality comparisons with floats.

Floating-point numbers are stored in scientific notation. There are a certain number of bits designated for the exponent, etc. Any number that can't be exactly represented this way within the available bits of precision (like 0.1) will get rounded off. Exactly where depends on both the hardware doing the floating point math and how many bits of precision the math is being done at.