【发布时间】:2014-05-27 03:15:08
【问题描述】:
在 C++ 中,您可以使用 int,它通常是 4 个字节。 long long 整数通常是 8 个字节。如果 cpu 是 32 位的,那不是将其限制为 32 位数字吗?如果 long long 不支持 64 位,我怎么能使用它? alu 可以加更大的整数吗?
【问题讨论】:
-
参见 Knuth Vol 2,第 4.3 节
在 C++ 中,您可以使用 int,它通常是 4 个字节。 long long 整数通常是 8 个字节。如果 cpu 是 32 位的,那不是将其限制为 32 位数字吗?如果 long long 不支持 64 位,我怎么能使用它? alu 可以加更大的整数吗?
【问题讨论】:
大多数处理器都包含一个进位标志和一个溢出标志,以支持对多字整数的操作。进位标志用于无符号数学,溢出标志用于有符号数学。
例如,在 x86 上,您可以添加两个无符号 64 位数字(我们假设它们在 EDX:EAX 和 EBX:ECX 中),如下所示:
add eax, ecx ; this does an add, ignoring the carry flag
adc edx, ebx ; this adds the carry flag along with the numbers
; sum in edx:eax
也可以在 C++ 等高级语言中实现这种功能,但它们支持它的工作要少得多,因此代码通常最终会比用汇编语言编写时慢得多。
大多数操作本质上基本上是串行的。当您在二进制级别进行加法时,您需要两个输入位并产生一个结果位和一个进位位。然后在添加下一个最低有效位时将进位位用作输入,以此类推(称为“波纹加法器”,因为加法会在整个字中“波纹”)。
当特定的加法不产生依赖关系时,有更复杂的方法可以减少一个位和另一个位之间的依赖关系,并且大多数当前的硬件都使用这样的东西。
然而,在最坏的情况下,将1 添加到一个已经是给定字长支持的最大数字上将导致从每个位到下一个位生成一个进位,一直到整个字。
这意味着(至少在某种程度上)CPU 支持的字宽限制了它可以运行的最大时钟速度。如果有人非常想这样做,他们可以构建一个可以处理 1024 位操作数的 CPU。但是,如果他们这样做,他们将有两个选择:要么以较低的时钟速度运行它,要么花费多个时钟来添加一对操作数。
还请注意,当您像这样扩展操作数时,您需要更多的存储空间(例如,更大的缓存)来存储尽可能多的操作数,需要更多的门来执行每个单独的操作,等等。
因此,如果采用相同的技术,您可以拥有一个运行频率为 4 GHz 并具有例如 4 MB 缓存的 64 位处理器,或者运行频率约为 250 MHz 并且可能具有 2 MB 缓存的 1024 位处理器缓存。
如果您的大部分工作都是在 1024 位(或更大)的操作数上完成的,那么后者可能会是一个胜利。大多数人根本不经常对 1024 位操作数进行数学运算。事实上,64 位数字对于大多数用途来说已经足够大了。因此,在大多数情况下,支持更广泛的操作数可能会成为大多数人的净损失。
【讨论】:
基本上通常的单指令加法分为两个(或三个)步骤:
1) 使用通常的加法指令将低 32 位相加。注意这个加法是否会产生一个“执行”位(也就是说,如果结果实际上需要 33 位来表示)。
2) 以相同方式添加高 32 位。如果低位有进位,请在此处设置进位位(或者,在相加后将结果加一)。
【讨论】:
可以支持任意宽的整数(通过软件实现),即使底层硬件直接只支持较少的位。如果一个 32 位整数与另一个 32 位整数相加,它可能会溢出并需要 33 位来存储答案。软件可以检测到发生了这种溢出(处理器有一个可以检查的carry flag),另一个表示64位数字的最高有效位的32位字可以加1。
Here's a little more 关于进位标志及其使用方式。
【讨论】:
您使用两个内存位置来存储数字。一半的数字存储在内存中的一个位置,另一半存储在相邻的内存位置。
【讨论】:
您可能还认为,在 8 位 CPU 时代,我们曾经处理 16 位甚至 32 位大小的整数。除了内存空间之外,没有什么可以限制任何特定的 alu 处理任意大小的数字,最终我想是用户的耐心。
例如,自最初的 Dorados 和 Altos 以来,Smalltalk 一直提供任意长度的整数 - 这将我们带回到 1970 年。想要 963 的确切值! - 去做就对了。不过,格式化它需要一段时间才能打印。
【讨论】: