Search code examples
c#performancecalculationprocessing-efficiency

Curious case of efficiency of equation algorithm, why are more operations faster?


I lately wrote a bit that shall smooth out the extends of a 0-1 range. Out of curiousity I measured the performance of two possibilities to acchieve the same end result. What came out is that this:

_ = (Mathf.Sin(-1.57079633f + (time * 3.14159265f)) + 1) * 0.5f; // Sin + 4o

faster than this

_ = Mathf.Cos(time * 3.14159265f) * -0.5f + 0.5f; // Cos + 3o

even though the former has more operations? And it's not faster by just some tiny bit, it's approximately 31% faster. For time t a constant of 0.5f was used.

There's no difference in using Sin or Cos for either, I did test for that in case the algorithm behind those functions would be the cause. Since Mathf is a Unity thing i tested it using System.Math. as well to make sure this isn't the cause, the results are roughly the same exept that System.Math. is overall a tiny bit slower since it calculates a double that then has to be cast to a float (Single).

Is Someone able to enlighten me why this is the case? I'd be interessted in undestanding why this is.

Addendum: Testing code

var sw = new System.Diagnostics.Stopwatch();
sw.Start();
for (int i = 0; i < 500000; i++)
{
    _ = (Mathf.Sin(-1.57079633f + (time * 3.14159265f)) + 1) * 0.5f; // Sin + 4o
}
sw.Stop();
print($"Sin calc time = {sw.ElapsedTicks * 0.0001f}ms ({sw.ElapsedMilliseconds}ms)");
sw.Restart();
for (int i = 0; i < 500000; i++)
{
    _ = Mathf.Cos(time * 3.14159265f) * -0.5f + 0.5f; // Cos + 3o
}
sw.Stop();
print($"Cos calc time = {sw.ElapsedTicks * 0.0001f}ms ({sw.ElapsedMilliseconds}ms)");

Solution

  • When using a value of 0.5 for time, the call to Math.Sin() ends up calling Math.Sin(0) - and I suspect that the implementation of Math.Sin() has an optimisation for that case that just returns 0.

    The value passed to Math.Cos(), however, will be ~1.5707963705062866, and it's likely that this will NOT have a similar optimisation.

    The fact that your time value was const also means that the compiler can pre-calculate the values passed to Math.Sin() and Math.Cos() which means that it doesn't matter if the calculation for Math.Sin() contains more operations, since they will not be performed at run-time.