[英]Fastest way to sum digits in a number
給定一個很大的數字,例如9223372036854775807
( Int64.MaxValue
),對數字求和的最快方法是什么?
目前我將Toctringing並將每個char重新分解為一個int
:
num.ToString().Sum(c => int.Parse(new String(new char[] { c })));
這肯定是非常無懈可擊的。 有什么建議么?
最后,你將如何使用BigInteger
進行這項工作?
謝謝
那么,另一種選擇是:
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];
}
這意味着迭代次數減少,但每次迭代都有一個增加的數組訪問權限......
沒有人討論過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 )的問題。 在一個新的水平,你有另外2 -1.2Ø(K 1.6)工作4個問題大小O((K / 4)1.6)的。 將所有項和2的冪加起來變成一個收斂於常數的幾何級數,因此總工作量為O(k 1.6 )。
這是一個明確的勝利,如果你正在使用數千個數字的數字,那么勝利將非常非常明顯。
是的,這可能有些低效。 我可能只是重復除以10,每次加上余數。
性能優化的第一條規則:當你可以相乘時,不要分開。 以下功能將采用四位數字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位數字,因此固定點乘法的中間結果不會溢出。
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;
而不是int.parse,為什么不從每個數字中減去'0'來獲得實際值。
請記住,'9' - '0'= 9,所以你應該能夠按照k(數字的長度)來做到這一點。 減法只是一個操作,所以不應該減慢速度。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.