从理论上讲,0 和 255 之间的比较是否比 0 和 1 快?
Theoretically, is comparison between 0 and 255 faster than 0 and 1?
从非常底层编程的角度来看,两个数字之间的比较是如何进行的?
使用一个字节,写入无符号数0、1和255:
0 -----> 00000000
1 -----> 00000001
255 ---> 11111111
现在,比较这些数字时会发生什么?
以我作为一个学习了基本编程的人的眼光,我可以想象以下关于 ==
实现的算法:
b = 0
while b < 8:
if first_number[b] != second_number[b]:
return False
b += 1
return True
基本上这就像逐个比较每个位,如果两个位不同则在结束前停止。
因此我们注意到,比较在第一次迭代比较 0 和 255 时停止,而如果比较 0 和 1,它在最后一次迭代停止。
第一次比较比第二次快 8 倍。
实际上,我怀疑情况是否如此。但这在理论上是正确的吗?
如果不是,计算机是如何工作的?
当涉及到汇编时,无论变量的内容如何,都会使用 cmp
指令。
所以没有性能差异。
整数之间的比较通常由 cpu 作为减法实现,其结果符号包含有关哪个数字更大的信息。
虽然简单的减法实现一次执行一位(因为每一位都需要知道前一位的进位),但典型的实现使用进位先行电路,允许在同时.
所以,答案是:不,每个可能的输入的每次比较都花费几乎相同的时间。
硬件与主流编程范式有着根本的不同,因为所有逻辑门(或一般电路)总是始终独立、并行地完成它们的工作。没有"do this, then do that",只有"do this here, feed the result into the circuit over there"。如果芯片上有一个输入 A 和输出 B 的电路,那么该电路总是根据 A 的当前值不断地更新 B — 不管现在是否需要结果 "in the big picture".
您的伪代码算法甚至没有开始很好地映射到逻辑门。相反,比较器在 Verilog 中看起来像这样(忽略有一个内置的 ==
运算符):
assign not_equal = (a[0] ^ b[0]) | (a[1] ^ b[1]) | ...;
其中每个 XOR 都是一个单独的逻辑门,因此独立于其他逻辑门工作。结果是 "reduced" 逻辑或,即如果任何 XOR 产生 1,则输出为 1(这也会并行执行一些工作,但关键路径比一个门长)。此外,无论具体的位值如何,所有这些门都存在于硅中,并且对于 w 位整数,信号必须通过大约 (1 + log w) 个门传播。此传播延迟再次独立于中间结果和最终结果。
在某些CPU系列中,相等比较是通过将两个数相减并将结果与零进行比较来实现的(使用如上所述的电路),但适用相同的原理。 adder/subtracter 不会根据值变慢或变快。
更不用说 CPU 中的指令无论如何都不能少于一个时钟周期,所以即使硬件可以更快地完成,下一条指令仍然要等到下一个时钟周期才会开始.
现在,一些 硬件操作可能需要不同的时间,但那是因为它们是状态机,即顺序逻辑。 技术上可以用状态机实现你的算法的道德等价物,但没有人这样做,它比上面朴素的、未优化的组合电路更难实现,而且启动效率较低.
状态机电路是带有存储器的电路:它们存储当前状态并始终在每个时钟周期计算输出(取决于当前状态)和下一个状态(取决于当前状态和输入)。在某些输入上,它们可能会经历 N 个状态,直到它们产生输出,而在其他输入上可能会经历 N+x 个状态。不过,ALU 操作通常不会这样做。流水线停顿、分支预测错误和高速缓存未命中是在某些情况下一条指令比平时花费更长的时间的常见原因。以帮助程序员编写更快代码的方式正确推理这些是困难的:您必须考虑 真实 硬件的所有棘手和怪癖,并且有很多。经验证据,即对真实黑盒进行基准测试 CPU,是至关重要的。
从非常底层编程的角度来看,两个数字之间的比较是如何进行的?
使用一个字节,写入无符号数0、1和255:
0 -----> 00000000
1 -----> 00000001
255 ---> 11111111
现在,比较这些数字时会发生什么?
以我作为一个学习了基本编程的人的眼光,我可以想象以下关于 ==
实现的算法:
b = 0
while b < 8:
if first_number[b] != second_number[b]:
return False
b += 1
return True
基本上这就像逐个比较每个位,如果两个位不同则在结束前停止。
因此我们注意到,比较在第一次迭代比较 0 和 255 时停止,而如果比较 0 和 1,它在最后一次迭代停止。
第一次比较比第二次快 8 倍。
实际上,我怀疑情况是否如此。但这在理论上是正确的吗? 如果不是,计算机是如何工作的?
当涉及到汇编时,无论变量的内容如何,都会使用 cmp
指令。
所以没有性能差异。
整数之间的比较通常由 cpu 作为减法实现,其结果符号包含有关哪个数字更大的信息。
虽然简单的减法实现一次执行一位(因为每一位都需要知道前一位的进位),但典型的实现使用进位先行电路,允许在同时.
所以,答案是:不,每个可能的输入的每次比较都花费几乎相同的时间。
硬件与主流编程范式有着根本的不同,因为所有逻辑门(或一般电路)总是始终独立、并行地完成它们的工作。没有"do this, then do that",只有"do this here, feed the result into the circuit over there"。如果芯片上有一个输入 A 和输出 B 的电路,那么该电路总是根据 A 的当前值不断地更新 B — 不管现在是否需要结果 "in the big picture".
您的伪代码算法甚至没有开始很好地映射到逻辑门。相反,比较器在 Verilog 中看起来像这样(忽略有一个内置的 ==
运算符):
assign not_equal = (a[0] ^ b[0]) | (a[1] ^ b[1]) | ...;
其中每个 XOR 都是一个单独的逻辑门,因此独立于其他逻辑门工作。结果是 "reduced" 逻辑或,即如果任何 XOR 产生 1,则输出为 1(这也会并行执行一些工作,但关键路径比一个门长)。此外,无论具体的位值如何,所有这些门都存在于硅中,并且对于 w 位整数,信号必须通过大约 (1 + log w) 个门传播。此传播延迟再次独立于中间结果和最终结果。
在某些CPU系列中,相等比较是通过将两个数相减并将结果与零进行比较来实现的(使用如上所述的电路),但适用相同的原理。 adder/subtracter 不会根据值变慢或变快。
更不用说 CPU 中的指令无论如何都不能少于一个时钟周期,所以即使硬件可以更快地完成,下一条指令仍然要等到下一个时钟周期才会开始.
现在,一些 硬件操作可能需要不同的时间,但那是因为它们是状态机,即顺序逻辑。 技术上可以用状态机实现你的算法的道德等价物,但没有人这样做,它比上面朴素的、未优化的组合电路更难实现,而且启动效率较低.
状态机电路是带有存储器的电路:它们存储当前状态并始终在每个时钟周期计算输出(取决于当前状态)和下一个状态(取决于当前状态和输入)。在某些输入上,它们可能会经历 N 个状态,直到它们产生输出,而在其他输入上可能会经历 N+x 个状态。不过,ALU 操作通常不会这样做。流水线停顿、分支预测错误和高速缓存未命中是在某些情况下一条指令比平时花费更长的时间的常见原因。以帮助程序员编写更快代码的方式正确推理这些是困难的:您必须考虑 真实 硬件的所有棘手和怪癖,并且有很多。经验证据,即对真实黑盒进行基准测试 CPU,是至关重要的。