有一个很酷的技巧可以用固定宽度的整数对二进制中的 1 位数字进行求和。在每次迭代中,您将一半的数字分成两个值,向下移动一个值,然后相加。第一次迭代,分隔其他数字。第二次迭代、数字对等。
鉴于 27 是 8 位二进制的 00011011,该过程是......
00010001 + 00000101 = 00010110 <- every other digit step
00010010 + 00000001 = 00010011 <- pairs of digits
00000011 + 00000001 = 00000100 <- quads, giving final result 4
您可以对十进制执行类似的技巧,但它的效率会低于简单循环,除非您可以直接表示十进制数,并通过快速操作将所选数字归零并进行数字移位。所以对于 12345678 你会得到......
02040608 + 01030507 = 03071115 <- every other digit
00070015 + 00030011 = 00100026 <- pairs
00000026 + 00000010 = 00000036 <- quads, final result
因此 1+2+3+4+5+6+7+8 = 36,这是正确的,但只有当您的数字表示形式是固定宽度十进制时,您才能有效地执行此操作。它总是需要 lg(n) 次迭代,其中 lg 表示以 2 为底的对数,并且向上舍入。
为了对此进行一些扩展(基于评论中的讨论),让我们pretend这是理智的,有一点……
如果你计算个位数的加法,实际上有more这里比简单的循环更有效。与按位计数技巧一样,这个想法是对这些加法重新排序(使用关联性),然后并行计算尽可能多的加法,使用单个全角加法来实现两个半角加法,四个四分之一宽度添加等。数字清除和数字移位操作的开销很大,如果将其实现为循环(计算或查找每个步骤的数字掩码和移位距离值),则开销甚至更大。 “循环”可能应该完全展开,并且这些掩码和移位距离应作为常量包含在代码中以避免这种情况。
处理器支持二进制编码十进制 (BCD) http://en.wikipedia.org/wiki/Binary-coded_decimal可以处理这个。数字掩码和数字移位将使用位掩码和移位来实现,因为每个十进制数字将被编码为 4(或更多)位,独立于其他数字的编码。
一个问题是 BCD 支持现在相当罕见。它曾经在 8 位和 16 位时代相当常见,但据我所知,现在仍然支持它的处理器主要是为了向后兼容。原因包括...
非常早期的处理器不包括硬件乘法和除法。对这些操作的硬件支持意味着现在可以更轻松、更高效地将二进制转换为十进制。现在几乎所有东西都使用二进制,而 BCD 几乎被遗忘。
库中有十进制数字表示形式,但很少有高级语言为硬件 BCD 提供可移植支持,因此,由于汇编程序不再是大多数开发人员的现实选择,BCD 支持就不再被使用。
随着数字变大,即使是压缩的 BCD 压缩效率也相当低。以 10^x 为基数的数字表示形式具有以 10 为基数最重要的属性,并且很容易解码为十进制。基数 1000 每三位数字只需要 10 位,而不是 12 位,因为 2^10 是 1024。这足以表明您获得了 32 位的额外十进制数字 - 9 位而不是 8 位 - 并且您仍然剩下 2 位,例如对于一个符号位。
问题是,要使这种数字总计算法完全有价值,您需要使用可能至少为 32 位(8 位数字)的固定宽度小数。这为(完全展开的)简单循环提供了 12 次操作(6 个掩码、3 个移位、3 个加法),而不是 15 个加法。不过,这只是一个临界增益——代码中的其他问题很容易意味着它实际上会更慢。
64 位(16 位十进制数字)的效率增益更为明显,因为仍然只有 16 个操作(8 个掩码、4 个移位、4 个加法)而不是 31 个,但找到支持 64 位 BCD 操作的处理器的可能性似乎很小。即使您这样做了,您多久需要一次?似乎不太值得为此付出努力并失去可移植性。