C#中最快的按位运算

3

在C#中,任何特定的位运算(与、或、异或等)是否比其他运算更快?

我提出这个问题是因为我知道,在硬件方面,大多数东西都是使用NAND门构建的,因为几个NAND门可以复制任何其他门。这是否对高级编程语言产生任何影响?还是所有的抽象层中间使它们以相同的速度运行。

我意识到从这里获得的任何性能提升都是微不足道的,我只是出于好奇问一下。

编辑:请停止尝试解释为什么需要了解这个没有功能上的原因。这只是好奇心。

然而,我正在通过对两个数字执行一些位运算来生成HashCode。使用最便宜/最快的操作是有意义的。再次强调,这不会有任何区别,我只是好奇。

编辑:我的问题归结为这个:硬件在较低级别上依赖于NAND门,这是否会对较高级别的进程产生影响。这会导致NAND比XOR更快吗?

我出于对硬件细节如何影响软件的好奇心而提出这个问题。这对我来说很有趣。


2
性能提升不是微不足道的,而是无限小的。此外,在明显不需要的情况下,代码质量>代码优化。 - Pierre-Luc Pineault
2
无论如何,我只是喜欢理解。 - Nealon
不要试图进一步扩展 - 编写高性能代码的最佳方法是首先设置性能目标,然后编写您可以想到的最直接的方法来实现功能。然后,您需要测量性能,如果不可接受,您需要对代码进行分析以确定要集中精力的区域 - 或者甚至发现您的算法工作在错误的复杂度顺序上。您不会通过在每个步骤上微观分析每个可能的替代方案并尝试将它们组合来编写高性能代码。 - Damien_The_Unbeliever
“我想知道最快的操作方式”和“我不想编写高性能代码”这两个陈述是相互矛盾的。 - Damien_The_Unbeliever
@Damien_The_Unbeliever 我并不是在尝试提高编程技能。再次强调,我只是好奇而已。 - Nealon
显示剩余9条评论
2个回答

7

在C#中,任何特定的位运算(AND、OR、XOR等)是否比其他运算更快?

我已经创建了一个基准测试:

Random r = new Random();
int a = r.Next();
int b = r.Next();
int c = 0;
Stopwatch sw = new Stopwatch();

sw.Start();
for (int i = 0; i < int.MaxValue; i++)
{
    c += a & b;
}
sw.Stop();
Console.WriteLine("AND operator: {0} ticks", sw.Elapsed.Ticks);
Console.WriteLine("Result: {0}", c);
c = 0;
// The above is just to make sure that the optimizer does not optimize the loop away,
// as pointed out by johnnycrash in the comments.
sw.Restart();
for (int i = 0; i < int.MaxValue; i++)
{
    c += a | b;
}
sw.Stop();
Console.WriteLine("OR operator: {0} ticks", sw.Elapsed.Ticks);
Console.WriteLine("Result: {0}", c);
c = 0;
for (int i = 0; i < int.MaxValue; i++)
{
    c += a ^ b;
}
sw.Stop();
Console.WriteLine("XOR operator: {0} ticks", sw.Elapsed.Ticks);
Console.WriteLine("Result: {0}", c);
c = 0;
for (int i = 0; i < int.MaxValue; i++)
{
    c += ~a;
}
sw.Stop();
Console.WriteLine("NOT operator: {0} ticks", sw.Elapsed.Ticks);
Console.WriteLine("Result: {0}", c);
c = 0;
for (int i = 0; i < int.MaxValue; i++)
{
    c += a << 1;
}
sw.Stop();
Console.WriteLine("Left shift operator: {0} ticks", sw.Elapsed.Ticks);
Console.WriteLine("Result: {0}", c);
c = 0;
for (int i = 0; i < int.MaxValue; i++)
{
    c += a >> 1;
}
sw.Stop();
Console.WriteLine("Right shift operator: {0} ticks", sw.Elapsed.Ticks);
Console.WriteLine("Result: {0}", c);

它会输出以下内容:
AND operator: 7979680 ticks
OR operator: 7826806 ticks
XOR operator: 7826806 ticks
NOT operator: 7826806 ticks
Left shift operator: 7826806 ticks
Right shift operator: 7826806 ticks

AND运算符需要更长的时间,因为它是第一个循环。如果我比如交换AND和OR循环的顺序,那么OR循环需要更多的时间。


在我的系统上,优化器会将操作从循环中提取出来,因此所测量的只是循环计数器的增加和测试。 - johnnycrash
实际上,由于结果 c 从未被使用,所以被测试的代码完全被移除了。 - johnnycrash
@johnnycrash 如果你禁用优化,它能正常工作吗? - ProgramFOX
如果在WriteLine语句中添加“c”,并保留优化,它就能正常工作。似乎可以将其添加到第一个writeln中,优化器会在所有循环中计算c。优化器并不那么令人印象深刻...此外,<< 1看起来是使用mov eax,a,add eax,eax实现的,而不是使用shift。 - johnnycrash
通常情况下,当您编写像您所做的那样的循环时,在每个循环中将一个值设置为相同的值,优化器会消除循环并一次执行计算。我总是要查看反汇编并更改我的测试以愚弄优化器。通常我最终会累加测试,例如c += a >> (i&31),并且您始终需要输出计算结果,以便它看起来像使用了结果。 - johnnycrash
显示剩余9条评论

5
CPU是一个同步逻辑引擎,由时钟驱动。这些低级操作都在单个指令中执行。

1
一个OR操作可能会在一个周期内完成,但是在代码中使用OR操作可能会导致从内存中加载一个或两个值,执行操作,并潜在地将结果存回内存。 - Servy
这对我来说很有意义,尽管它是一个稍微令人失望的答案。谢谢! - Nealon
@Servy:这会对AND或XOR有何影响? - user1196549
@YvesDaoust 事实上,你从来没有只执行其中一个操作;如果你在测量/比较它们,那么你几乎肯定是主要在测量其他东西。 - Servy
@Nealon:实际上,现代处理器的行为非常复杂(流水线执行、多个流水线、推测性分支和执行、缓存级别),以至于它几乎是不确定的。同一条指令在不同的上下文中可能具有极大的延迟差异。真正的改进是通过确保良好的局部性、避免数据依赖和禁止分支来实现的。 - user1196549
@Servy:从汇编或高级语言的角度来看,AND/OR/XOR是等效的指令(操作数数量相同,ALU的使用类似)。它们不应该引起不同的行为,即使考虑到加载/存储或其他额外的编译器优化。 - user1196549

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接