float vs double

Started by
48 comments, last by GameDev.net 18 years, 7 months ago
Quote:Original post by RobTheBloke
on the bog standard 0x86 FPU, all calcs happen at 80bits, whether they are double or float. however, the 0x86 can read only 4bytes at a time. So (assuming that the data is 4byte aligned), a double requires 2 reads to get it into memory, a float requires a single read.


Just to clarify, entire blocks of 4k will be read out of main memory and into L1 cache at a time. These will then be loaded into registers as needed. The latter step isn't especially intensive. The thing is though, that the 4k will only fit half as many doubles as floats.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Advertisement
Quote:Original post by Daniel Miller
If you shouldn't use == or !=, then wouldn't > and < be messed up as well?


No, < and > are fine. The problem with == and != is that rounding errors could turn what you think is 1.234567 into 1.234693, and if you try to == it with 1.234567, it'll return false, when it actually should be true. On the other hand, 1.234693 is still, say, < 0. You only have a problem if you compare 2 numbers that are very close to each other.
at university they told us that some implementations tend to round up the last bit of the mantissa if you have a large positive exponent

although i don t know why they don t implement a hardware epsilon comparsion since the binary comparsion is
a) actually quite useless in most cases
b) could be don t by integer comparsions or bitwise and
(float pointer to intpointer, reference & right operand)
http://www.8ung.at/basiror/theironcross.html
Quote:Original post by MauMan
Quote:
NEVER EVER use == on a float


Sometimes I've thought to myself that using == or != on a float or double should arguably be a compiler warning.

I have to disagree. It's the best way to test for NaN. For instance,
f != f   // returns true if f is NaNf == f   // returns false if f is NaNf == NaN // always returns falsef != NaN // always returns true


I usually use a utility method to determine if numbers are sufficiently close, e.g.,
public static bool EpsilonEquals(double f1, double f2, double epsilon){  // Returns true if f1 is closer than epsilon to f2.  return (Math.Abs(f1 - f2) <= epsilon);}

or for inequalities,
public static bool EpsilonGreaterThan(double f1, double f2, double epsilon){  // Returns true if f1 is greater than f2 within tolerance.  return ((f1 - epsilon) > f2);}


public static bool EpsilonGreaterThanEqualTo(double f1, double f2, double epsilon){  // Returns true if f1 is greater than or equal to f2 within tolerance.  return ((f1 - epsilon) >= f2);}
- k2"Choose a job you love, and you'll never have to work a day in your life." — Confucius"Logic will get you from A to B. Imagination will get you everywhere." — Albert Einstein"Money is the most egalitarian force in society. It confers power on whoever holds it." — Roger Starr{General Programming Forum FAQ} | {Blog/Journal} | {[email=kkaitan at gmail dot com]e-mail me[/email]} | {excellent webhosting}
Quote:
Very true, a most useful function for any program dealing with floating values:

bool compareFloat ( float Value1 , float Value2 , float Tolerance )
{
if ( fabs ( Value1 - Value2 ) < Tolerance )
return true ;
else
return false ;
}

The tolerance can be hard coded if desired.


Actually, that's an improvement over == but still not great... http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm explains why, and suggests better methods. (Anyone know how to make that a link? I tried but that doesn't work).
Quote:Original post by BittermanAndy
(Anyone know how to make that a link? I tried but that doesn't work).<!--QUOTE--></td></tr></table></BLOCKQUOTE><!--/QUOTE--><!--ENDQUOTE--><br><br>Use HTML.<br><br><pre>&lt;a href="http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm"&gt;http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm&lt;/a&gt;<br> -&gt;<br><a href="http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm">http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm</a></pre>
Yet again benchmarking?

Floats are, if used on SSE2 registers, aproximately 2 times faster than Doubles. It might look great, but it would apply only on larger matrices. I would rather have 2x slowdown, than did more often test for rounding errors and played with error cancelation. If you can use double it's not often worthy to play with floats even for slight speed increase. (BTW they are IIRC equally fast on common FPU registers.) One important situation when floats might be neccessary is transfer of prepared data to GFX card. However IIRC there might be problems if exponents would be too large.
Actually there are other situations when float might be of some importance. Div, and sqrt. With these 40 - 80 CPU cycles instructions the half data size might be important. However majority of developers are using

c = 1D/divider
for ... ca[...] = something[...] * c

One operation on high precision number will not kill the above code. Low precision data member might.

As a general rule, if you will work with data that would remain in computer memory use double. If you work with data that needs to be transfered to GFX, and they need to be transfered as a floating point use float (because your GFX card is highly likely is unable to use double, and bandwidth required would kill AGP3.0 / PCIE data transfer)

Also it looks like you'd need some decoupling of your 3D engine, game engine, and world engine.

BTW if anyone would like to play with benchmarking of floats and doubles, try scimark. It has some ability to measure speed differences.
Dividing by a very small double can be just as disastrous as dividing by a very small float. Doubles represent a greater range than floats, but in general it is best to avoid dividing by numbers close to 0, possibly by rewriting the code in a way that avoids the division or checks for values close to 0.

It is similiar to how you never use == to compare two floating point numbers and instead check to see if they are within some epsilon value. If the denominator is very close to 0 it is safer to treat it as if it was 0. If you're dividing by a number that might be 0, don't use == to compare it to 0, use the epsilon test method.

Graphics cards can internally use whatever precision they want, possibly even something different than 32 bit or 64 bit. At certain stages they even tend to use higher precisions to avoid certain artifacts. But for displaying geometry, 32 bit accuracy is plenty.
Quote:Original post by Daniel Miller
If you shouldn't use == or !=, then wouldn't > and < be messed up as well?

Yes, but the effect is usually less significant.

e.g.

This may return false:
11.1f / 11.1f == 8.0f / 8.0f


And this could return true:
11.1f / 11.1f < 8.0f / 8.0f


The difference is that there's only 1 value out of 2^32 that make the first one true, however in the second case there's roughly 2^31 values that make it true. So if you're off by 1 bit for ==, it may never return true, whereas if you're off by 1 bit for <, it'll fix itself next iteration. You can have stability problems though if the calculation "lands" on the threshold and thus cause it to iterate true/false/true/true/false/true instead of a clean false/false/false/true/true/true.

Compares on float ought to be "fuzzy" and anything that's within the eplison should be considered equal.

		struct scalar			{			typedef float float_t;			scalar() {}			explicit scalar(float_t f) : f(f) {}			float_t f;			//...			};		inline bool operator==(scalar a, scalar b)			{			return abs(b-a).f < std::numeric_limits<scalar::float_t>::epsilon();			}		inline bool operator!=(scalar a, scalar b)			{			return !(a==b);			}		inline bool operator<(scalar a, scalar b)			{			return (a.f<b.f) && (a!=b);			}			
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Quote:Original post by Anonymous Poster

Graphics cards can internally use whatever precision they want, possibly even something different than 32 bit or 64 bit. At certain stages they even tend to use higher precisions to avoid certain artifacts. But for displaying geometry, 32 bit accuracy is plenty.


ATI used 24 bits of precision for long time, they didn't delayed switching to 32 bits just for nothing. That 8 bit lower precision caused a some advantage in speed in comparison to pure FP32 bit registers on more advanced cards. Actually majority of registers are 4xFP32, and FP16 has also its place.
32 bits might be plenty if you have environment smaller than 16E6 units, and you never do any multiplication. 32 bit precision might be horrible for scaling and rotation of 3D models. When I used some Bethesda software, I could see theirs geometry precision was by few units smaller, than was neccessary to prevent fall through geometry. ^_^

This topic is closed to new replies.

Advertisement