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();
}
}
8条答案
按热度按时间sxpgvts31#
有关http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs如何在不使用分支的情况下计算绝对值,请参阅www.example.com。
虽然.Net支持内联,但我怀疑编译器是否会考虑将
Math.Abs()
作为内联的候选对象。其他整数类型的重载也是类似的。
float
和double
重载是外部调用,而decimal
重载使用自己的实现,它构造了一个新的示例。哎哟!n7taea2i2#
C#会执行内嵌Math.Abs。这是可行的:
qlckcl4x3#
C#执行内联
Math.Abs()
,下面是Math.Abs
的C#和汇编代码(使用在线工具SharpLab生成):C#:
组装:
snvhrwxg4#
如果你知道它是关于例如一个最小化问题的差异,你可以使用:a〈b?b-a:a-b
vojdkbi05#
我做了一些性能测试,看看除了标准的Math. Abs之外,使用其他工具是否真的可以节省时间。
执行所有这些2000000000次后的结果(
i
从-1000000000到+1000000000,因此没有溢出):(这些数字因运行不同而略有不同)
基本上你可以得到一个非常轻微的改善比
Math.Abs
,但没有什么壮观的。使用bit hack可以节省一点Math.Abs所需的时间,但可读性会受到严重影响。
有了简单的分支,你实际上可以慢一点。总体来说,在我看来不值得。
所有测试均在32位操作系统、Net 4.0、VS 2010、发布模式下运行,未连接调试器。
下面是实际代码:
jtw3ybtb6#
JIT在某些情况下执行内联。我不知道它是否内联
Math.Abs
......但您是否验证过这实际上对您来说是一个性能问题?在您知道需要微优化之前,不要进行微优化,然后通过以下方式测量性能增益:来验证它是否值得。
正如Anthony所指出的,上面的代码(通常)对
int.MinValue
不起作用,因为-int.MinValue == int.MinValue
,而Math.Abs
将抛出OverflowException
。您也可以在直接的C#中使用检查算法强制执行此操作:thtygnil7#
实际上,一个32位带符号的2的补码格式int的绝对值通常是这样实现的:
绝对值(x)=(x^(x〉〉31))-(x〉〉31)
rqenqsqc8#
我只看它是否小于零,然后乘以-1