.NET实现:Math.Min中的双重转换(float,float)

时间:2012-03-27 08:29:48

标签: .net math double type-conversion reflector

为什么.Net实现了Math.Min(float,float)函数,如下所示:

public static float Min(float val1, float val2)
{
  if ((double) val1 < (double) val2 || float.IsNaN(val1))
    return val1;
  else
    return val2;
}

虽然我可以看到使用IsNaN但我不明白为什么在比较值时它们会转换为double。这不比简单地写val < val 2慢吗?特别是如果我想用它来将数字钳位到数字而不太精确,例如0f1f

我是否应该继续实施一个自定义数学库,另外还需要具有非NaN值以获得最佳性能,还是浪费时间?

public static float Min(float a, float b)
{
    return a < b ? a : b;
}

4 个答案:

答案 0 :(得分:5)

  

是的,我使用了Resharper,它正是这样做的

这就是问题所在,它会使代码失误。源代码可从Reference Source获得,如下所示:

  [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;
  }

很难猜出为什么Resharper这样做,我很容易认为它只是一个bug。支持Microsoft提供的源代码,不仅仅是为了准确,但评论也很好。

答案 1 :(得分:2)

我无法告诉你为什么他们选择将float投射到double进行比较,但我怀疑它会对你的程序产生明显或显着的速度影响。我只是使用内置函数。

答案 2 :(得分:1)

没有Math.Min(float,float)这样的东西。 .NET仅包含Min(double,double)的定义。 查看MSDN:http://msdn.microsoft.com/en-us/library/system.math.min(v=vs.100).aspx

编辑:有,谢谢@gideon http://msdn.microsoft.com/en-us/library/070xee48.aspx

答案 3 :(得分:1)

通常,您不能认为Single的执行速度比Double快。 Intel CPU上的浮点寄存器为80位,CPU上的浮点运算使用该精度执行。在该平台上,JIT可以生成浮点指令,将参数加载到本机80位寄存器中,唯一的区别在于寄存器是从32位还是64位存储器位置加载的。也许Math.Min的实现者基于JIT编译器如何生成浮点代码的复杂知识来实现​​它们。

从接受的答案可以看出,问题是基于错误的假设(从SingleDouble的演员表)。为了调查转换是否确实有所不同,我查看了Min函数生成的汇编程序,有或没有强制转换。

这是我在调试器中看到的.NET框架Math.Min(Single, Single)

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 

以下是使用强制转换为Double的函数的程序集,就像问题一样:

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 

还有一些说明,这些可能会略微降低功能的性能。