最快的方法来对数字中的数字求和

时间:2011-03-11 17:53:35

标签: c# math sum digits

如果数量很大,例如9223372036854775807Int64.MaxValue),求数的最快方法是什么?

目前我正在将每个字符串解析并重新分析为int

num.ToString().Sum(c => int.Parse(new String(new char[] { c })));

这肯定是非常无懈可击的。有什么建议吗?

最后,你会如何使用BigInteger

来完成这项工作

由于

6 个答案:

答案 0 :(得分:14)

嗯,另一种选择是:

int sum = 0;
while (value != 0)
{
    int remainder;
    value = Math.DivRem(value, 10, out remainder);
    sum += remainder;
}

BigInteger也有DivRem方法,因此您可以使用相同的方法。

请注意,我已经看到DivRem没有“手动”执行相同算术那么快,所以如果你真的对速度感兴趣,你可能会想到

还要考虑一个查找表,其中包含(例如)预先计算了总和的1000个元素:

int sum = 0;
while (value != 0)
{
    int remainder;
    value = Math.DivRem(value, 1000, out remainder);
    sum += lookupTable[remainder];
}

这意味着更少的迭代,但每次迭代都有一个添加的数组访问...

答案 1 :(得分:2)

没有人讨论过BigInteger版本。为此,我会看10 1 ,10 2 ,10 4 ,10 8 等等,直到你发现最后10个 2 n 小于你的价值。取你的数字div和mod 10 2 n 得出2个较小的值。洗净,冲洗并递归重复。 (你应该在一个数组中保留10的迭代方块,并在递归部分传递有关下一个要使用的功率的信息。)

对于具有k个数字的BigInteger,除以10是O(k)。因此,使用朴素算法求数位的总和为O(k 2 )。

我不知道C#在内部使用什么,但用于将k位乘以或除以k位整数的非天真算法都在时间上起作用O(k 1.6 )或者更好(大多数都好多了,但是有一个开销使得它们对于“小整数”来说更糟)。在这种情况下,准备你的初始权力列表和分裂一次需要时间O(k 1.6 )。这给出了2个大小为O((k / 2) 1.6 )= 2 -0.6 O(k 1.6 )的问题。在下一个级别,你有4个问题,大小为O((k / 4) 1.6 )另一个2 -1.2 O(k 1.6 )工作。将所有项和2的幂加起来变成一个收敛于常数的几何级数,所以总的工作是O(k 1.6 )。

这是一个明确的胜利,如果你正在处理成千上万位的数字,那么胜利将非常非常明显。

答案 2 :(得分:1)

是的,这可能有些低效。我可能只是重复除以10,每次都将余数加在一起。

答案 3 :(得分:1)

性能优化的第一条规则:当你可以相乘时,不要分开。以下功能将采用四位数字0-9999并按照您的要求进行操作。中间计算大于16位。我们将数字乘以1/10000并将结果作为Q16定点数。然后通过乘以10并取整数部分来提取数字。

#define TEN_OVER_10000 ((1<<25)/1000 +1) // .001 Q25

int sum_digits(unsigned int n)
{
    int c;
    int sum = 0;
    n = (n * TEN_OVER_10000)>>9; // n*10/10000 Q16
    for (c=0;c<4;c++)
    {
    printf("Digit: %d\n", n>>16);
        sum += n>>16;
        n = (n & 0xffff) * 10; // next digit
    }
    return sum;
}

这可以扩展到更大的尺寸,但它很棘手。您需要确保定点计算中的舍入始终正常。我也做了4位数字,因此固定点乘法的中间结果不会溢出。

答案 4 :(得分:0)

    Int64 BigNumber = 9223372036854775807;

    String BigNumberStr = BigNumber.ToString();
    int Sum = 0;

    foreach (Char c in BigNumberStr)
        Sum += (byte)c;

    // 48 is ascii value of zero
    // remove in one step rather than in the loop
    Sum -= 48 * BigNumberStr.Length;

答案 5 :(得分:0)

为什么不从每个数字中减去'0'而不是int.parse,以获得实际值。

记住,'9' - '0'= 9,所以你应该能够按照k(数字的长度)来做到这一点。减法只是一个操作,所以不应该减慢速度。