Skip to content
Tech News
← Back to articles

Unity vs. Floating Point

read original get Unity 3D Floating Point Guide → more articles
Why This Matters

This article highlights the nuances of floating-point precision in Unity, revealing that many math functions default to double precision, which can impact performance and accuracy. Understanding these differences is crucial for developers aiming to optimize their game physics and calculations, especially in performance-critical applications.

Key Takeaways

A tweet by @VehiclePhysics sparked my interest. It basically says:

For most math functions (Sqrt, Sin, Cos, Log, Pow…), prefer System.MathF over UnityEngine.Mathf . Unity’s Mathf casts to double, calls the double version, then converts back to float. System.MathF calls the float-native implementations directly. Less work, same result.

This advice is basically correct! But turns out, things are slightly more complicated.

Hidden double precision in Unity

The advice above applies to all UnityEngine.Mathf methods that deal with trigonometry ( Sin , Cos , Tan , Asin , Acos , Atan , Atan2 ), exponentials ( Sqrt , Pow , Exp , Log , Log10 ), rounding ( Ceil , Floor , Round , CeilToInt , FloorToInt , RoundToInt ), comparisons ( Min , Max , Clamp , Clamp01 ) and others ( Sign , SmoothStep , Gamma , Approximately , InverseLerp ). About the only function it does not apply to is Mathf.Abs .

But… why? Well, because C#/.NET originally did not have single-precision methods for these sorts of math functions. The single precision System.MathF was introduced in .NET Core 2.0 (year 2017).

Now, you might have expected that almost ten years later, maybe Unity would have noticed this, and made them single precision? Alas, no. There could be potential backwards compatibility issues preventing that (or maybe not! see below).

You also might have guessed that Unity.Mathematics package, which was introduced (year 2019) as part of the whole DOTS push, and is modeled to be very similar to HLSL, would actually do single precision floating point for functions that look like single precision floating point… and that would be wrong too; for all the trigonometric and exponential functions like math.sqrt(float x) it routes that into the double precision C# implementation. Why? I don’t know.

But wait! There is way more double precision. The Mono C# runtime used in Unity does all math in double precision, everywhere. Yes, this means there is a ton of float⭤double conversions from in-memory representation to in-register representation, all over the place. I have first noticed this back in 2018 when doing a toy path tracer, and then Miguel de Icaza did an explanatory blog post, with plans outlined how to switch Mono to use actual floats for floats (yeah!).

“In Mono, decades ago, we made the mistake of performing all 32-bit float computations as 64-bit floats while still storing the data in 32-bit locations.”

... continue reading