快速整数ABSfunction

int X = ab; int d = Math.Abs(X); 

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

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

 int d = X > 0 ? X : -X; 

validation它真的值得。

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

 int d = X > 0 ? X : checked(-X); 

我做了一些性能测试,以确定你是否可以使用除标准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 

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

基本上你可以比Math.Abs略微改进,但没什么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(); } } 

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

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

我只是看它是否小于零并乘以-1

 int d = (X < 0) ? (-X) : X; 

有关如何在不进行分支的情况下计算绝对值,请参阅http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs 。

虽然.Net支持内联,但我怀疑Math.Abs()会被编译器视为内联的候选者。 这是int重载的实现,由Reflector提供。

 public static int Abs(int value) { if (value >= 0) { return value; } return AbsHelper(value); } private static int AbsHelper(int value) { if (value == -2147483648) { throw new OverflowException(Environment.GetResourceString("Overflow_NegateTwosCompNum")); } return -value; } 

其他整数类型的重载是类似的。 floatdouble重载是外部调用,而decimal重载使用它自己的实现,它构造一个新实例。 哎哟!

C#内联Math.Abs​​。 这有效:

 int x = 12; int y = 17; int z = Math.Abs(x - y); Console.WriteLine(z); //outputs 5