不久前,我在一个数学论坛上看到一个问题,一个人一次又一次地讨论将数字中的数字相加,直到得到一个数字。(即"362“会变成"3+6+2”,变成“11”……则"11“将变为"1+1”,将变为"2“,因此"362”将返回2...我写了一些很好的代码来得到这个问题的答案,并发布了它,结果被一个用户超越了,这个用户建议模9的任何数字都等于这个“无限数字和”,我检查了一下,他是对的……嗯,几乎是对的,如果返回0,你必须用"9“把它换出来,但这是一个非常快速的修复方法……
362 = 3+6+2 = 11 = 1+1 =2
或者..。
362%9 =2
通常,mod9方法可以无限地将数字的和相加,直到只剩下一个数字为止……但是如果只做一次呢(即362只会返回“11”)……有人能想到快速算法吗?
发布于 2013-02-19 13:52:35
用二进制和固定宽度的整数对1进行求和有一个很酷的技巧。在每次迭代中,您将每个数字的一半分成两个值,将一个值向下移位,然后相加。第一次迭代,分隔所有其他数字。第二次迭代、成对的数字等等。
假设27是00011011的8位二进制,那么这个过程是...
00010001 + 00000101 = 00010110 <- every other digit step
00010010 + 00000001 = 00010011 <- pairs of digits
00000011 + 00000001 = 00000100 <- quads, giving final result 4您可以对decimal使用类似的技巧,但它的效率不如简单的循环,除非您有一个直接表示十进制数的快速操作,可以将选定的数字置零并进行数字移位。所以你花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表示以两为底的对数,你向上舍入。
为了对此稍作扩展(基于评论中的讨论),让我们假装这是正常的,稍微...
如果你计算个位数的加法,实际上比一个简单的循环有更多的工作。这个想法,与计数位的逐位技巧一样,是重新排序这些加法(使用结合性),然后并行计算尽可能多的加法,使用单个全宽加法来实现两个半宽加法,四个四分之一宽加法等。数字清除和数字移位操作的开销很大,如果您将其实现为循环(计算或查找每一步的数字掩码和移位距离值),则开销会更大。“循环”可能应该完全展开,这些掩码和移位距离应该作为常量包含在代码中,以避免这种情况。
支持Binary Coded Decimal (BCD)的处理器可以处理此问题。数字掩码和数字移位将使用比特掩码和比特移位来实现,因为每个十进制数字将被编码为4个(或更多)比特,而与其他数字的编码无关。
一个问题是,BCD支持现在非常少见。它曾经在8位和16位时代相当普遍,但据我所知,现在仍然支持它的处理器主要是为了向后兼容。原因包括……
问题是,为了让这个数字总和算法有价值,您需要使用可能至少32位(8位)的固定宽度小数。这给出了12个操作(6个掩码,3个移位,3个加法),而不是(完全展开的)简单循环的15个加法。不过,这只是一个边际收益--代码中的其他问题很容易意味着它实际上更慢。
64位(16位十进制数)的效率提升更加明显,因为仍然只有16次操作(8个掩码,4次移位,4次加法),而不是31次,但找到支持64位BCD操作的处理器的可能性似乎很小。即使你这样做了,你又需要多久一次呢?这似乎不太可能是值得的努力和可移植性的损失。
发布于 2013-02-19 13:35:21
以下是Haskell中的一些内容:
sumDigits n =
if n == 0
then 0
else let a = mod n 10
in a + sumDigits (div n 10)哦,但我刚看到你已经这么做了.
(然后还有一个显而易见的事实:
sumDigits n = sum $ map (read . (:[])) . show $ n)
发布于 2013-04-04 12:07:11
要获得简短的代码,请尝试以下代码:
int digit_sum(int n){
if (n<10) return n;
return n%10 + digit_sum(n/10);
}或者,用语言来说,
数字小于10,那么数字-If就是数字本身。
-Otherwise,数字和是当前的最后一个数字(也称为N mod10或n%10),加上该数字左侧所有数字的数字和(n除以10,使用整数除法)。
-This算法也可以推广到任何基数,用中的基数代替10。
https://stackoverflow.com/questions/14950422
复制相似问题