Math.Atan2 and FPATAN

本文关键字:FPATAN and Atan2 Math | 更新日期: 2023-09-27 18:10:07

我正在用c#编写一些数学代码,迫使它在发行版中为x86编译,经过优化,并且我正在查看windbg中的反汇编。它通常都很好,经常写得比我还好(并不是说我很擅长汇编,但就是这样)。

但是,我注意到这个函数:

static void TemporaryWork()
{
    double x = 4;
    double y = 3;
    double z = Math.Atan2(x, y);
}

正在产生这个反汇编:

001f0078 55              push    ebp
001f0079 8bec            mov     ebp,esp
001f007b dd05a0001f00    fld     qword ptr ds:[1F00A0h]
001f0081 83ec08          sub     esp,8
001f0084 dd1c24          fstp    qword ptr [esp]
001f0087 dd05a8001f00    fld     qword ptr ds:[1F00A8h]
001f008d 83ec08          sub     esp,8
001f0090 dd1c24          fstp    qword ptr [esp]
001f0093 e86e9ba66f      call    clr!GetHashFromBlob+0x94e09 (6fc59c06) (System.Math.Atan2(Double, Double), mdToken: 06000de7)
001f0098 ddd8            fstp    st(0)
001f009a 5d              pop     ebp
001f009b c3              ret

即使你不是x86专家,你也会注意到一些奇怪的地方:这里有一个对System.Math.Atan2的调用。如在函数调用中。

但实际上有一个x86操作码可以做到这一点:FPATAN

当有一个实际的汇编指令来做操作时,为什么JITer调用一个函数?我以为那个系统。数学基本上是本机汇编指令的包装器。那里的大多数操作都有直接的汇编操作码。但事实显然并非如此?

有没有人知道为什么JITer没有/不能执行这个相当明显的优化?

Math.Atan2 and FPATAN

你可以从这个答案中找到原因,它显示了这些数学函数是如何被抖动映射的。

它带你到clr/src/classlibnative/float/comfloat.cpp, ComDouble::Atan2()函数。这就解释了原因:

   // the intrinsic for Atan2 does not produce Nan for Atan2(+-inf,+-inf)
   if (IS_DBL_INFINITY(x) && IS_DBL_INFINITY(y)) {
       return(x / y);      // create a NaN
   }
   return (double) atan2(x, y);

所以这是一个解决方法来修复FPU行为不符合CLI。