这两个代码片段中的第一个如何在执行更多工作时比第二个代码片段快3倍?

Sim*_*itt 6 c# performance x86 jit x86-64

这段代码怎么样:

var check = 0;

for (var numerator = 0; numerator <= maxNumerator; numerator++)
{
    check += numerator >= 0
           ? numerator - (int) ((numerator * qdi.Multiplier) >> qdi.Shift) * qdi.Number
           : numerator - (int) -((-numerator * qdi.Multiplier) >> qdi.Shift) * qdi.Number;
}

return check;
Run Code Online (Sandbox Code Playgroud)

运行速度比此代码快3倍:

var check = 0;

for (var numerator = 0; numerator <= maxNumerator; numerator++)
{
    check += numerator >= 0
           ? (int) ((numerator * qdi.Multiplier) >> qdi.Shift)
           : (int) -((-numerator * qdi.Multiplier) >> qdi.Shift);
}

return check;
Run Code Online (Sandbox Code Playgroud)

第一个代码片段执行完全相同的快速除法运算(即乘法然后右移),但也进行减法和乘法,但JIT编译器似乎产生较慢的代码.

我有每个可用的反汇编代码.
较慢的代码推送rbx寄存器并在开始时从rsp中减去10h,然后将其加回并在结束时弹出rbx,而较快的代码则不会.
较慢的代码也使用r11寄存器来处理更快的代码使用rdx的大多数事情.

有任何想法吗?

Sim*_*itt 1

看来三元运算中使用的条件影响生成的代码。

看起来三元选项生成的代码效率比简单的 if/else 低。

因此,将第二个片段中的循环代码更改为:

if (numerator >= 0) check += (int) ((numerator * qdi.Multiplier) >> qdi.Shift);
else check += (int) -((-numerator * qdi.Multiplier) >> qdi.Shift);
Run Code Online (Sandbox Code Playgroud)

或者:

if (numerator < 0) check += (int) -((-numerator * qdi.Multiplier) >> qdi.Shift);
else check += (int) ((numerator * qdi.Multiplier) >> qdi.Shift);
Run Code Online (Sandbox Code Playgroud)

或者:

check += numerator < 0
    ? (int) -((-numerator * qdi.Multiplier) >> qdi.Shift)
    : (int) ((numerator * qdi.Multiplier) >> qdi.Shift);
Run Code Online (Sandbox Code Playgroud)

将产生运行速度更快的代码。

实际上,我觉得有点令人不安的是,四分之三的组合会产生快速的代码,但另一种会产生缓慢的代码......有时。