参考自:http://www.cnblogs.com/herbert/archive/2011/02/13/1953943.html
Project Euler problem 16
215 = 32768 and the sum of its digits is 3 + 2 + 7 + 6 + 8 = 26.
What is the sum of the digits of the number 21000?
计算 2 的 1000次方的所有数字的和?
这个设计大数乘方问题,通用的思路就是采用数组来分段处理大数,分段表示大数。下面的算法中,我采用的是“万进制”,用数组来存储数据。
原理如下:
先说计数方法:
比如
2 的 26次方
num= 67108864
我们可以这样来写这个数:
6710 8864
令arr[0] = 6710, arr[1] = 8864
那么,arr数组看起来就象和67108864是一样的
看到这里你明白了吧?
我们可以分段表示一个非常大的数而不必考虑它的溢出,
而只用考虑段数是否大于一个数即可
举个例子:
上边,单段的最大值是9999,每段不溢出
那么,num就不会溢出
再一个乘法.
我们老祖宗给我们留下的算盘,很妙,
它其实就是最基本的计算机之一
我们算乘方时,
只用乘以一个数:
这样来列式子:
123456790
*2=
--------------
246913580
即:
123 456 790
*2= *2= *2=
----- ----- ------
246 912 (1)580(溢出) 第三段有溢出,加到上一段
----- ----- --------
246 913 580
呵呵,就这样,打算盘一样,进位.
最后是我自己(cutebear)用c#写的,测试通过:
private static string BigNumberPow(int baseNumber, int power)
{
// Math.Log10(x^y) = y * Math.Log10(x).
// 估计结果有多少位。
double rawDigitCount = power * Math.Log10((double)baseNumber);
double digitCount = (int)(Math.Ceiling(rawDigitCount));
// 这里用万进制,即满一万进1,运算过程用数组来存放,数组中每一个的最大值是9999。
// 除以4,得到所需的数组的长度。
int arrayLength = (int)(Math.Ceiling((double)(digitCount / 4.0)));
int[] numbers = new int[arrayLength];
int jinweinumber = 0;
// 模拟人工运算,设置初始值。
numbers[arrayLength - 1] = baseNumber;
// 由于设置了初始值,所以需要乘以baseNumber共power -1次。
for (int j = 1; j < power; j++)
{
// 对每一段乘以baseNumber,注意进位的值要加到前一段。
for (int i = arrayLength - 1; i >= 0; i--)
{
if (numbers[i] == 0 && jinweinumber == 0)
continue;
numbers[i] = numbers[i] * baseNumber;
numbers[i] += jinweinumber;
if (numbers[i] > 9999)
{
var quyu = numbers[i] % 10000;
jinweinumber = (numbers[i] - quyu) / 10000;
numbers[i] = quyu;
}
else
jinweinumber = 0;
}
}
StringBuilder result = new StringBuilder();
for (int i = 0; i < arrayLength; i++)
{
// 不足四位的前面补0。
result.Append(numbers[i].ToString("0000"));
}
return result.ToString().TrimStart('0');
}
同理,下面是计算大数的阶乘:
private static string JieCh(int n)
{
// 使用万进制,每个数组元素四位,估计用来存计算结果所需数组的长度。
int arraylength = 50;
int[] numbers = new int[arraylength];
numbers[arraylength - 1] = 1;
for (int j = 2; j <= n; j++)
{
int jinweinumber = 0;
for (int i = arraylength - 1; i >= 0; i--)
{
numbers[i] *= j;
numbers[i] += jinweinumber;
if (numbers[i] > 9999)
{
var quyu = numbers[i] % 10000;
jinweinumber = (numbers[i] - quyu) / 10000;
numbers[i] = quyu;
}
else
jinweinumber = 0;
}
}
StringBuilder result = new StringBuilder();
for (int i = 0; i < arraylength; i++)
{
result.Append(numbers[i].ToString("0000"));
}
return result.ToString().TrimStart('0');
}