快速整数ABS功能

Dan*_*dor 9 .net c# optimization

int X = a-b;
int d = Math.Abs(X);
Run Code Online (Sandbox Code Playgroud)

我很确定.NET不会内联.那么,我会做if(),还是还有其他一些鲜为人知的技巧?

Hug*_*une 17

我做了一些性能测试,以确定你是否可以使用除标准Math.Abs​​之外的其他东西来节省时间.

执行所有这些2000000000次后的结果(i从-1000000000到+1000000000,所以没有溢出):

Math.Abs(i)                    5839 ms     Factor 1
i > 0 ? i : -i                 6395 ms     Factor 1.09
(i + (i >> 31)) ^ (i >> 31)    5053 ms     Factor 0.86
Run Code Online (Sandbox Code Playgroud)

(这些数字因不同的运行而有所不同)

基本上你可以得到一个非常小的改善Math.Abs,但没有什么了不起的.

有点破解你可以减少Math.Abs​​所需的一些时间,但可读性严重受损.
使用简单的分支,您实际上可以更慢.在我看来总的来说不值得.

所有测试均在32位操作系统,Net 4.0,VS 2010,发布模式下运行,不附带调试器.

这是实际的代码:

class Program
{
    public static int x; // public static field. 
                         // this way the JITer will not assume that it is  
                         // never used and optimize the wholeloop away
    static void Main()
    {
        // warm up
        for (int i = -1000000000; i < 1000000000; i++)
        {
            x = Math.Abs(i);
        }

        // start measuring
        Stopwatch watch = Stopwatch.StartNew();
        for (int i = -1000000000; i < 1000000000; i++)
        {
            x = Math.Abs(i);
        }
        Console.WriteLine(watch.ElapsedMilliseconds);

        // warm up
        for (int i = -1000000000; i < 1000000000; i++)
        {
            x = i > 0 ? i : -i;
        }

        // start measuring
        watch = Stopwatch.StartNew();
        for (int i = -1000000000; i < 1000000000; i++)
        {
            x = i > 0 ? i : -i;
        }
        Console.WriteLine(watch.ElapsedMilliseconds);

        // warm up
        for (int i = -1000000000; i < 1000000000; i++)
        {
            x = (i + (i >> 31)) ^ (i >> 31);
        }

        // start measuring
        watch = Stopwatch.StartNew();
        for (int i = -1000000000; i < 1000000000; i++)
        {
            x = (i + (i >> 31)) ^ (i >> 31);
        }
        Console.WriteLine(watch.ElapsedMilliseconds);


        Console.ReadLine();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 支持实际执行基准测试并提供相关基准测试环境详细信息 (2认同)
  • 在 x64 处:5764 4191 4026 (2认同)
  • 锐龙 3800X、dotnet 核心 3.1:855、1407、950。 (2认同)

Jon*_*eet 15

JIT在某些情况下执行内联.我不知道它是否内联Math.Abs......但你确认这实际上是一个性能问题吗?在您知道需要之前不要进行微观优化,然后通过以下方式测量性能增益:

int d = X > 0 ? X : -X;
Run Code Online (Sandbox Code Playgroud)

验证它真的值得.

正如由Anthony指出,上面就不会(通常)为工作int.MinValue,如-int.MinValue == int.MinValue,而Math.Abs将引发OverflowException.您可以使用选中的算法在直接C#中强制执行此操作:

int d = X > 0 ? X : checked(-X);
Run Code Online (Sandbox Code Playgroud)

  • 那些干涉最低价值的人! (3认同)
  • 在我的计算机上,当我循环遍历"[Int32.MinValue + 1,Int32.MaxValue - 1]"范围内的所有整数值时,上面的第一个表达式比"Math.Abs​​"快8倍.当我在`-x`上应用`checked`时,完整循环的加速(负_和_正值)减少到只快4倍.它当然取决于替换`Abs`函数需要的一般性,但鉴于`checked`增加了相当多的开销来保证`Int32.MinValue`的一致处理,所以放弃`checked`可能是值得的.在大多数情况下. (3认同)
  • `checked(-X)` - 很好.没有想到这一点. (2认同)

Ada*_*ith 6

对于它的价值,32位带符号,2的补码格式int的绝对值通常是这样实现的:

abs(x)=(x ^(x >> 31)) - (x >> 31)

  • 由另一位宇宙大师获得专利:http://www.patentgenius.com/patent/6073150.html (2认同)
  • (x + (x &gt;&gt; 31)) ^ (x &gt;&gt; 31) 效果同样好,并且没有获得专利(即使该专利可能在法庭上无效)。检查此页面上的评论:http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs (2认同)