Vector2.Distance() is slooooooooow.....

For those that are not aware, using the Vector2.Distance() method is extremely slow compared to just doing the calculation…

By a factor of around 3.4+ times slower…

When I ran it:

diff2 was 67.9991
diff3 was 236.0034

Fairly significant difference.

Some Test Code:

        DateTime startTime;
        DateTime endTime;
        double answer;
        double diff2;
        double diff3;
        Vector2 pos1 = new Vector2(10, 10);
        Vector2 pos2 = new Vector2(50, 50);

        startTime = DateTime.Now;
        for (int i = 0; i < 10000000; i++)
        {
            pos1.X = 100;
            pos1.Y = 100;

            pos2.X = 500;
            pos2.Y = 500;

            answer = Math.Sqrt((pos2.X - pos1.X) * (pos2.X - pos1.X) + (pos2.Y - pos1.Y) * (pos2.Y - pos1.Y));
        }

        endTime = DateTime.Now;

        diff2 = (endTime - startTime).TotalMilliseconds;

        startTime = DateTime.Now;
        for (int i = 0; i < 10000000; i++)
        {
            pos1.X = 100;
            pos1.Y = 100;

            pos2.X = 500;
            pos2.Y = 500;

            answer = Vector2.Distance(pos1, pos2);
        }

        endTime = DateTime.Now;

        diff3 = (endTime - startTime).TotalMilliseconds;

Seems kind of strange! This is the code for Vector2.Distace from the MG Github repo:

public static float Distance(Vector2 value1, Vector2 value2)
{
    float v1 = value1.X - value2.X, v2 = value1.Y - value2.Y;
	return (float)Math.Sqrt((v1 * v1) + (v2 * v2));
}

If anything that should be more efficient (unless double to float is killing it).

1 Like

There are some previous considerations to this message:

First, your difference of ~3.4 is around ~2 for me. That’s because you’re either using the MonoGame debug DLL, or you’re compiling your speed test project with Debug, or you’re running your project with F5 (instead of Ctrl+F5), or a combination of those. When testing speeds it’s better to test the “really release mode” (that’s MG release, release compilation, and Ctrl+F5)

Second, DateTime is not an accurate way to measure short amounts of time. It’s better to use Stopwatch.

That said, the reason it’s slower is that the Vector2.Distance call is not inlined, so a call is made. This is always slower than an inlined code execution. When in doubt about this kind of things, launch ILSpy and have a look at the generated code.

Workarounds? You could mark the Vector2.Distance in monogame source code as Aggressive Inlining, but I’m not sure if it’ll work. I’m not an expert but I think that the JIT plays a big role in inlining, so, being the code in another assembly it’s possible that the Vector2.Distance is inlined depending on the JIT. You may get it inlined in net core 3, but not on a previous version.

2 Likes

Additionally the method call has to convert the float back to double to store it in ‘answer’.
To make a fair comparison you should make double float and call ‘answer = (float)Math.Sqrt((pos2.X - pos1.X) * (pos2.X - pos1.X) + (pos2.Y - pos1.Y) * (pos2.Y - pos1.Y));’

My guess is that most of the cycles are wasted on copying the two vectors.
Try the faster Vector2.Distance(ref pos1, ref pos2, out answer);

3 Likes

necropost

This is a common problem because Microsoft’s Math.Sqrt() uses double, so it’s accurate and slow.

Might be worth looking into a less accurate float/int version of Sqrt that’s “close enough”. An integer value is close enough in most cases.

It depends why are you trying to get the distance, my personal advice is that if you want just to compare between two or more distances to know which one is closer or farther from your reference point use the distance square to compare how far those points are, so I don’t do the Math.Sqrt and save a lot of cycles, I get the same result since I don’t care about the distance value but I care about the order.

3 Likes

Use MathF instead of Math if you don’t need better precision than float/single.

I just checked, Monogame is using MathF internally in 3.8.1. So go ahead and use the Vector operations all you want.

Otherwise I completely agree, if you’re using Math anywhere in your game code you almost certainly should be using MathF instead.

@SL2 & @Quasar,

Thank you for posting about MathF. For some reason I wasn’t aware of this and was using Math for calculations when MonoGame’s library didn’t have the features I needed. Flows much nicer using MathF with floating point numbers.

-Brett