How to edit Mathf algorithms and calculations?

I was wondering if its possible to change Mathf algorithms. If not, how can i get the Mathf.Sqrt code (to make an external method and change the external method) ? The reason i want it is because right now, the Mathf.Sqrt code calculates the square root to 5 decimal places of accuracy, but i only need 3 decimal places of accuracy, so alot of processing power is wasted.

First an foremost, it’s technically not 5 decimal places of accuracy. It’s that a ā€˜float’ is returned, which can hold roughly 6 to 9 sig values (fractional or whole) depending the number (it’s a binary value so it’s ranges don’t map well to decimal). You usually end up with about 7, 6 guaranteed. If you’re calculating the square root of say 10, you get about 3.16227… the float no longer can really hold values pass that as it doesn’t have the bit depth to do it (the double which is actually doing the calculation is much larger).

So lets look at the source…

You can always decompile the UnityEngine.dll with something like dotpeek to get a look at the general code behind the methods. Though one problem with this is that usually it’s calling through to Unity itself (the C++ side, which is not source accessible), or is just wrapping around .Net/Mono methods.

After decompiling Mathf we find that the Sqrt method is a wrapper around .Net/Mono:

    /// <summary>
    ///
    /// <para>
    /// Returns square root of f.
    /// </para>
    ///
    /// </summary>
    /// <param name="f"/>
    public static float Sqrt(float f)
    {
      return (float) Math.Sqrt((double) f);
    }

Note how actually it’s using the System.Math method, which calculates on doubles. A double has even greater bit depth, so really, it’s calculating way more than 5 digits of accuracy, it’s calculating like 16 digits, which than get truncated down to 5 or 6.

So it’s calling through to Mono, which the source code is out there at the mono-project:
https://github.com/mono/mono
(technically this is the latest source, and Unity uses a slightly modified out-dated version… but we can get a general idea, I highly doubt Unity reimplemented Sqrt)

System.Math is here:

But again from the source:

[System.Security.SecuritySafeCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public static extern double Sqrt(double d);

It’s making a call to the internal implementation in the mono runtime, found here:

gdouble
ves_icall_System_Math_Sqrt (gdouble x)
{
if (x < 0)
return NaN.d;
return sqrt (x);
}

Which really just calls the cmath implementation (note the include <math.h> at the top):
http://www.cplusplus.com/reference/cmath/

So we’re actually calling a fairly robust algorithm for it.

You’re probably not going to get more efficient than this.

Though of course, there’s a good deal of overhead in the Mathf.Sqrt implementation because it:

  1. converts to double
  2. calls another method (new stack frame)
  3. calls another method (new stack frame)
  4. calculates sqrt
  5. returns back both stack frames
  6. converts to float
  7. finally returns closing last stack frame

You’re not going to overload this method either, you can’t change the underlying implementation.

BUT, you can write your own separately and just call that one. Call it CustomMath.Sqrt. You can then implement some fast but inaccurate algorithm you prefer… but I don’t suspect it will really give you any major performance increase that you’d really notice.

But maybe, at least now, you can see how you can research and dig through source code to find the answer to your original question about how it’s implemented.

11 Likes

Awesome answer!

1 Like

Id have to agree. Amazing answer, thanks so much! Considering i am using Sqrt millions of times per second, it is pretty important :wink: Also, in the Math.h source, its implemented here:

00361 inline double sqrt( double fValue )
00362 {
00363 return double( ::sqrt( fValue ) );
00364 }

http://ggt.sourceforge.net/html/Math_8h-source.html

If you are doing a lot of square roots and it’s causing performance problems, it would make a lot more sense to try to modify your algorithm to work with squares instead.

3 Likes

I dont want to create my own algorithm, because i have already tried it, and its actually slower than Mathf.Sqrt.

public static float Sqrt2(float z)
{
if (z == 0) return 0;
FloatIntUnion u;
u.tmp = 0;
float xhalf = 0.5f * z;
u.f = z;
u.tmp = 0x5f375a86 - (u.tmp >> 1);
u.f = u.f * (1.5f - xhalf * u.f * u.f);
return u.f * z;
}

[StructLayout(LayoutKind.Explicit)]
private struct FloatIntUnion
{
[FieldOffset(0)]
public float f;

[FieldOffset(0)]
public int tmp;
}

and then ā€œusing System.Runtime.InterlopServicesā€. I know i could add a lookup table or something, but i am not trying to compete with the Mathf.Sqrt algorithm, because it is extremely efficient when working out square root to 16 digits of precision. All i want to do is reduce the amount of iterations of Mathf.Sqrt, because its just wasted performance. If i am working out the square root to 16 digits of precision, and then just truncating it to 7 digits of precision , what it the point of all those extra iterations? And i dont even need 7 digits of precision, i only need three! I have looked at the source for Math.h, and it looks like it points to this: sourceware.org Git - glibc.git/blob - sysdeps/ieee754/dbl-64/e_sqrt.c Which looks like it doesnt point to anything else

This would be the sane path. Do you really need millions of square roots every single frame? Why not spread them out a bit with a coroutine or a thread. Or work in square space. Or just drop the overall precision of the algorithm using the roots.

1 Like

Maybe it is, but why do you care? There is a lot of wasted performance everywhere in your average game, it rarely matters at all. This sort of micro-optimization is just a waste of time unless you have finished your game and have identified this as a major performance bottleneck. Unless you see it as an academic exercise of course, then by all means have at it.

Come to think of it, sqrt is actually an FPU instruction, so the math.c implementation is probably only used as a fallback where it’s not supported. If I’m not mistaken, you are going to have a hard time beating that no matter how few digits you use.

2 Likes

Ok then… Thanks for the replies :slight_smile:

http://docs.unity3d.com/Manual/Profiler.html
https://unity3d.com/learn/tutorials/topics/interface-essentials/introduction-profiler
https://unity3d.com/learn/tutorials/topics/interface-essentials/profiler-overview-beginners

:slight_smile: