Reputation: 149
Why does .Net implement the Math.Min(float, float) function like so:
public static float Min(float val1, float val2)
{
if ((double) val1 < (double) val2 || float.IsNaN(val1))
return val1;
else
return val2;
}
While I can see the use of IsNaN I don't understand why they convert to double when comparing the values. Isn't that slower than simply writing val < val 2
? Especially if I wanted to use it to clamp a value to numbers without much precision like 0f
or 1f
.
Should I just go ahead and implement a custom math library which additionally also requires to have non NaN values to get the best performance or is that a waste of time?
public static float Min(float a, float b)
{
return a < b ? a : b;
}
Upvotes: 4
Views: 279
Reputation: 106826
In general you can't assume that Single
performs faster than Double
. The floating point registers on the Intel CPU's are 80 bits and floating point operations on the CPU are performed using that precision. On that platform the JIT may generate floating point instructions that load the arguments into the native 80 bit registers and only difference is if the registers are loaded from 32 bits or 64 bits memory locations. Perhaps the implementers of Math.Min
based their implementation on intricate knowledge of how the JIT compiler generates floating point code.
From the accepted answer it can be seen that the question is based on the wrong assumption (that there is a cast from Single
to Double
). To investigate if the cast actually does make difference I looked at the assembler generated by a Min
function with and without a cast.
This is the .NET framework Math.Min(Single, Single)
as seen in my debugger:
00000000 push ebp 00000001 mov ebp,esp 00000003 fld dword ptr [ebp+0Ch] 00000006 fld dword ptr [ebp+8] 00000009 fxch st(1) 0000000b fcomi st,st(1) 0000000d jp 00000015 0000000f jae 00000015 00000011 fstp st(1) 00000013 jmp 00000022 00000015 fcomi st,st(0) 00000017 jp 0000001B 00000019 je 00000026 0000001b mov eax,1 00000020 jmp 00000028 00000022 pop ebp 00000023 ret 8 00000026 xor eax,eax 00000028 test eax,eax 0000002a je 00000030 0000002c fstp st(1) 0000002e jmp 00000036 00000030 fstp st(0) 00000032 pop ebp 00000033 ret 8 00000036 pop ebp 00000037 ret 8
Here is the the assembly for a function using a cast to Double
just like in the question:
00000000 push ebp 00000001 mov ebp,esp 00000003 sub esp,8 00000006 fld dword ptr [ebp+0Ch] 00000009 fld dword ptr [ebp+8] 0000000c fld st(1) 0000000e fstp qword ptr [ebp-8] 00000011 fld qword ptr [ebp-8] 00000014 fld st(1) 00000016 fstp qword ptr [ebp-8] 00000019 fld qword ptr [ebp-8] 0000001c fcomip st,st(1) 0000001e fstp st(0) 00000020 jp 00000028 00000022 jbe 00000028 00000024 fstp st(0) 00000026 jmp 00000043 00000028 fxch st(1) 0000002a fcomi st,st(0) 0000002c jp 00000030 0000002e je 00000037 00000030 mov eax,1 00000035 jmp 00000039 00000037 xor eax,eax 00000039 test eax,eax 0000003b jne 00000041 0000003d fstp st(0) 0000003f jmp 00000049 00000041 fstp st(1) 00000043 mov esp,ebp 00000045 pop ebp 00000046 ret 8 00000049 mov esp,ebp 0000004b pop ebp 0000004c ret 8
There are a few more instructions and these will probably decrease the performance of the function slightly.
Upvotes: 1
Reputation: 941545
Yes, I used Resharper which does exactly that
And that's the problem, it fumbles the code. The source code is available from the Reference Source, it looks like this:
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static float Min(float val1, float val2) {
if (val1 < val2)
return val1;
if (Single.IsNaN(val1))
return val1;
return val2;
}
Hard to guess why Resharper does this, I'd readily assume its just a bug. Favor the source code available from Microsoft, not just for accuracy but the comments are nice too.
Upvotes: 5
Reputation: 2972
There's no such thing as Math.Min(float, float). .NET only contains a definition for Min(double, double). Check the MSDN: http://msdn.microsoft.com/en-us/library/system.math.min(v=vs.100).aspx
EDIT: there is, thanks @gideon http://msdn.microsoft.com/en-us/library/070xee48.aspx
Upvotes: 1
Reputation: 5304
I can't tell you why they chose to cast float
to double
for the comparison, but I doubt it's going to cause any noticeable or significant speed impact on your program. I'd just use the built-in function.
Upvotes: 2