- Home /
Performance of float.CompareTo
Hi good people, I'll go straight to the point. C# script. I was sorting a List
like this:
mColliders.Sort( (a, b) => ((a.Up.x-a.Radius).CompareTo(b.Up.x-b.Radius)));
and the performance on a ~250 long list were horrible, both in the editor and on the iPhone, roughly 3ms.
Then, just to test, I rewrote it with a dumb lamda like this:
mColliders.Sort( (a, b) => {
if (a.Up.x-a.Radius>b.Up.x-b.Radius) return 1;
else if (a.Up.x-a.Radius<b.Up.x-b.Radius) return -1;
else return 0;
});
Much better, went down to ~0.6ms. Does anybody here have an idea of why the CompareTo was being so damn slow?
Thanks!
The faster implementation of your sort would be to only do the calculation once:
mColliders.Sort( (a, b) => {
var diff = (a.Up.x - a.Radius) - (b.Up.x - b.Radius);
return diff < 0 ? -1 : (diff == 0 ? 0 : 1);
});
The point is the title, not the petty details. Why on earth would the implementation matter to you, since I'm asking specifically about CompareTo and it's in both implementations? Radius does not do any calculation, The lambda is willingly sloppy, to show how silly slow is the compareTo.
Also note you only need to return negative/0/positive, not necessarily -1/0/+1 -- so from @whydoidoit's comment above, just return diff directly.
Yap well aware of that. As I said, the lambda there is sloppy on purpose, to stress the inefficiency of the CompareTo.
@yoyo - note that the comparer needs an int, so the difference must be treated so that you don't return 0 for values like between -0.5f and 0.5f, in case you round, (-1, 1) if you truncate, etc. You can also scale the difference and just cast to int.
Answer by yoyo · May 16, 2013 at 05:20 AM
float.CompareTo is mostly likely converting a float value type into an object and then converting back to a value type. This boxing and unboxing process is slow, possibly worse in the iPhone .NET implementation.
$$anonymous$$ay well be, but it would be a terrible implementation of the fully typed version!
Just shows you can't trust the frameworks performance without actually measuring it :)
Totally agree with you. I tought about auto boxing but why would it do that with a float? If this is the case, horrible implementation fail.
What's the type of mColliders? Is it just List, or List(T)? If the latter then it shouldn't need to box the parameters. Either way, best way to find out for sure is to disassemble the IL and see what it's doing. Or just pick the fastest solution and move on ...
The tool of your choice: ILSpy ;)
It can decompile any .NET code into IL and most .NET code into C# (and VB .NET, well...)
This is actually the mscorlib (subset) version:
public int CompareTo(float value)
{
if (float.IsPositiveInfinity(this) && float.IsPositiveInfinity(value))
{
return 0;
}
if (float.IsNegativeInfinity(this) && float.IsNegativeInfinity(value))
{
return 0;
}
if (float.IsNaN(value))
{
if (float.IsNaN(this))
{
return 0;
}
return 1;
}
else
{
if (float.IsNaN(this))
{
if (float.IsNaN(value))
{
return 0;
}
return -1;
}
else
{
if (this == value)
{
return 0;
}
if (this > value)
{
return 1;
}
return -1;
}
}
}