Some of you may know that a while ago, another user ran some tests and found out that some math functions (primarily the Lerp functions) were slower than needed. He could write faster implementations which did the same thing as the built in ones. This resulted in Unity updating the built in functions to run faster.
I have run some tests to see if I could write faster implementations of some other Mathf functions, and it turned out that I could.
Especially the Approximately function could get super fast! It seems like it has become slower from 2.6, because I ran the same test script on 2.6 and then my implementation was āonlyā something like 250% faster.
It almost seems like I must have written faster, but incorrect code.
It looks like mostly the functions operating with intās are a lot slower than they could be.
Hereās a webplayer if you want to see for yourself - Mathf Performance Test ā Arongranberg.com
The script executes the functions 50000 times and measures the time it took for them to execute, then it compares it to my implementation and calculates a % value (100% equals no difference).
All values are random (refreshed every loop) and goes from -100000 to 100000⦠I think.
I have attached the script if anyone wants to take a look (had to attach it as .txt because the uploader didnāt want to upload a .cs file).
I remember that 2-3 months ago I was trying to optimize a low level C algorithm and I tried two different optimizations: one of them was much faster on my current desktop and the other one was faster in my 5-years-old laptop. So it is possible that your optimizations are faster in your computer but slower in other computers.
I have tested it on the two computers I have available, one old iMac and one new iMac, the implementations I wrote about in the first post were faster on both.
I posted a link to a webplayer so you can test it yourself, post your results!
Well thatās depressing to hear, especially for something like max() on an integer. Iād guess/hope thereāll be reasons for this beyond poor implementation.
I think your clamp methods can be faster if you put a single line like:
return a > c ? c : a < b ? b : a;
(similarly for Clamp01)
You avoid the re-assignment of āaā and the extra checks if āaā is greater than ācā. Although, I donāt know the current Unity behaviour if the user supplies garbage (min greater than max).
And the Lerp method could probably be made faster if the Mathf.Clamp call was skipped and its content copy/pasted into the method (avoid invoking the nested method), but that might not be the case unless the custom Clamp logic can be made equal/faster than the built-in Mathf.
Unity calls Monoās Math.Abs internally, so there is added method calling overhead. This is silly, so tomorrow Iām going to implement it so that we donāt waste time by calling into Mono.
Sign (float)
Clamp01 (float)
Unityās implementation is faster because you are doing comparison of floats vs ints. And then casting clamped results from int to float.
Sign (int)
Clamp01 (int)
Your implementation is faster because we donāt have overrides for ints so there are implicit casts. Iām going to add overrides tomorrow.
All of your clamps are doing an unnecessary ternary operation if the value is greater than the max.
Min (float)
Min (int)
Max (float)
Max (int)
Lerp (float)
These are identical to our implementations. And your test shows approx 100% on these, so that makes sense.
Approximately (float)
Your implementation degrades at larger values. For example, if both a and b are very big, but they are different by one bit, theyād logically be approximately the same. Your implementation would likely return false since adding/subtracting such a small constant would not be representable in such a low floating point resolution.
Also, itās very dangerous for us to change Approximately, since it may break backwards compatibility.
Repeat (float)
Your implementation does not work with negative values.
As long as youāre improving math functions, can you take a look at SpeedLerp? Mathf.Lerp, Mathf.InverseLerp, Mathf.SmoothStep, Vector2.Lerp, Vector3.Lerp, Vector4.Lerp, and Color.Lerp are all consistently slower than my own implementations across G5, Xeon, and ARM processors. It would be nice if you could make that script obsolete.
InverseLerp and SmoothStep are bit more involved so Iāll need to spend some time looking at our implementation, but quickly looking over our Lerps Iām not sure how they can be sped up. Iām curious what youāre doing to make them faster.
Looks like the only difference between the Lerps is that your implementation early outs when the value is outside of 0-1 range (instead of clamping) which is fair enough, but the worst case scenarios seem to be identical.
Ah. I knew it was to fast to be correct
Just out of curiosity, how does your implementation work?
And btw, why is U3s implementation of Approximately so much slower than U2.6s implementation?
When running the test on U3 I get 5000%, but on 2.6 I get around 300%, it might be my implementation which magically got faster on U3 though.
Ah, yeah, missed that.
ā200% faster is quite a lot though, I shall see if I can get it to work faster than yours and still get it to work with negative values.
ā¦
Okay, it seems like I canāt find a faster implementation of Repeat.
Hereās what I got, itās running at about 90-100% on Unity 2.6 (havenāt tested it on U3).
public static float Repeat (float a,float b) {
if (a < 0F) {
return b+(a % b);
}
return a % b;
}
It doesnāt return exactly the same values as the built-in though, when sending -20, 5, Mathf returns 0, but my implementation returns 5, both are correct though (0 <= 5 <= 5).