The title says it all, but I would like to know if I should use a double 1.5 for my velX and velY factor, or a float 1.5 for my velX and velY factor. Also, I would like to know if I should use a double or float for everything such as positions of entities, etc.. Thanks in advance!
-
\$\begingroup\$ That depends primarily on your specification - do you require the extra precision? Is the extra memory consumption a problem? .... \$\endgroup\$– UnholySheepFeb 18, 2017 at 16:15
-
\$\begingroup\$ stackoverflow.com/q/27598078/1889720 \$\endgroup\$– Evorlor ♦Feb 18, 2017 at 16:57
-
1\$\begingroup\$ Not going to lie, this is totally a micro optimization. If this is the difference between your game engine being able to keep up with your game or not, then you have made some other very serious errors along the way. \$\endgroup\$– corsiKaFeb 18, 2017 at 18:12
4 Answers
A double has a wider range than a float and use more memory. In your case it properly doesn't matter but the double is often the default option.
You can read more about it here: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
Both the single-precision 32-bit float
type and double-precision 64-bit double
type can represent numbers like 1.5 exactly, with no rounding error.
(ie. as 1 * 2^0 + 1 * 2^-1, followed by 22 zeroes in the case of a float
, or 51 zeroes in the case of a double
)
Neither one can exactly represent a number like one-fifth, 0.2, because its denominator is not a power of two. The closest you can get with a float
will be off by about 0.000 000 004, or four-billionths of a unit, and double
will get even closer.
Now I don't know about you, but I don't usually tune my game's meshes/colliders/speeds to tolerances of billionths of units, so in practice the precision limits of float
don't cause many problems in day-to-day game development calculations, as long as we're working within a few kilometers of the origin of our coordinate system - since both float
and double
use a sliding scale of precision, staying more precise for values close to zero, and trading-off some precision to represent bigger numbers. You can consult the table in this answer for the precision available in each range.
There are a few cases where the limits do crop up though:
Exact comparisons. Whether you're using
float
ordouble
, don't useif(myValue == thisTargetValue)
- because even a difference of billionths of a unit like we saw above is enough to make this comparison fail. Compare using ranges instead, so your code is tolerant to some fluctuation in the tiny final digits.Time. If you measure your time in seconds with a single-precision
float
, then if your game is left running for a day you'll be in a range where you start to lose millisecond precision, and that's usually enough to make sensitive timing code go haywire.float
is fine for accumulating time deltas like "how long has the player held the jump button," but don't use it for your global time.double
should be more than sufficient for games played over human lifespans though. This type of error has led to the failure of missile defense systems, so take it seriously. ;)Big Spaces. Once you go further than a few thousand units from the 0 point of your coordinate system, the precision limits of
float
tend to become significant. You can see this in Minecraft versions before Beta 1.8 - if you walk far enough in one direction, movement becomes jumpy and the terrain starts getting weird, as the errors grow to reach the sensitivity thresholds of the algorithms being used.3D rendering and physics engines usually work exclusively in single-precision
float
types, so changing absolutely everything over todouble
is generally not feasible. Instead, games with huge worlds usually solve this by breaking the world into chunks, and working with coordinates relative to the center of each chunk, rather than always in reference to the origin of the whole universe. Kerbal Space Program uses afloat
coordinate space with a "floating origin" that moves to keep the player centered, while an underlying orbital mechanics simulation usesdouble
values for computing the large-scale trajectories.Accumulated Error. An error of billionths in one calculation isn't much. But if you use that as input into another calculation, then use that output as another input, on and on in a feedback loop, then the errors can accumulate and snowball out of proportion.
A common way this can happen is if you store a transformation matrix for each object, and accumulate changes to the transformation directly into that matrix, without any error-correction. This often manifests as a spinning object gradually flattening or distorting.
Switching to
double
only delays the issue a little, because it's really a problem with our algorithm, allowing small errors to self-reinforce and magnify up to visible scales. Maintaining a separate, authoritative source value, or applying error-correction as you go, like normalizing direction vectors, can stop these errors from piling up to visible scales.
It pretty much boils down to how precise you want your world to be. Do you need to be able to move exactly 1 mm at a time or are you fine with just a rough estimate? In most cases I would go with floats as they get the job done most of the time, while also allowing for your game to potentially run faster because you only need half the amount of data in cache. If your game is very physics oriented(think Kerbal space program) then I would suggest using doubles instead.
It may also depend on 3rd party framework, engines & libraries. I.E. if you use doubles on your data structures, but your library uses floats, you may find that your doing a lot of casting. In turn, this may impact:
- Performance: This SO post suggests (down) casting isn't likely to degrade performance. That being said, sometimes microbenchmarks don't accurately portray what happens in actual production code - always profile before & after attempts to optimize.
- Precision & Accuracy: Down casting involves a loss of data. Up casting floats essentially fabricates data. Depending on your needs, this may result in precision &/or accuracy problems.
- Readability: Unless you've tweaked your compiler / IDE settings, down casts must be explicit, which can clutter up your code & reduce its readability.
- Safety: If you have tweaked your settings to permit implicit down casts, you run the risk of allowing unwanted &/or dangerous down casts to slip through.