我正在处理阶乘函数,具有大整数的阶乘会变得很长。
例如200000! = 973350位数字长,如果我只是使用ToString(),事情将花费很长时间。
200000!需要更长的时间才能转换为字符串,然后实际进行计算!
我尝试将阶乘函数设置为Process,然后使用ProcessorAffinity
将Thread固定到特定的内核,以便该内核仅转换为字符串,但这花费了完全相同的时间。
另外,我想将其转换为字符串的原因是因为我想将输出(FactFile)写入文本文件。
字符串转换代码:
using (Process proc = Process.GetCurrentProcess())
{
proc.ProcessorAffinity = (IntPtr)0x0003;
FactFile = Res.ToString(); //FactFile is Going to be the final string, Res is the Factorial.
}
这是我的阶乘代码:
for (BigInteger i = 1; i < k; i++)
{
Res *= i; // Res is the number to Calculate the factorial of
}
200000!需要15秒钟来计算,然后再花费18秒钟将其转换为字符串(这可能因CPU的不同而不同,我有一个i7)。
提醒:转换为字符串的最有效方法是什么?
输出:
Total Computation Time: 00:00:16.2007276
String Conversion Time: 00:00:19.4049292
答案 0 :(得分:1)
对于n!
上方的n = 24
,结果将比输入n
的值多位数。
数字的爆炸导致ToString
要做的工作要比阶乘(n-1
乘以more than n
除)。
但是,由于BigInteger
运算会根据其运算的数量而花费更长的时间,因此您可以先除以一个因子,例如对于您的200000!
示例:
var asString = Res.ToString()
对:
BigInteger[] bits = new BigInteger[2];
bits[0] = BigInteger.DivRem(Res, BigInteger.Pow(new BigInteger(10), 486675), out var remainder);
bits[1] = remainder;
var strs = new string[2];
System.Threading.Tasks.Parallel.For(0, 2, (i) =>
{
strs[i] = bits[i].ToString();
});
var asString = strs[0] + strs[1];
我发现这快了5秒,但是:
10^486675
的因子来均分数字-不确定您一般会怎么做DivRem
耗时8秒另请参阅一些现有的尝试,通过分拆工作来加快factorial calculation和bigint to base 10的运行。
第二个结论似乎是..不要将大的BigIntegers
转换为以10为底!
答案 1 :(得分:1)
这是40%更快的串词器。它将大整数重复除以数字10 ^ 10000,对其余部分进行字符串化处理,最后将所有字符串连接在一起。它也可以处理负数。
-std=c++11
通过将余数的字符串化处理卸载到后台线程中,可以稍微加快速度。不幸的是,算法最慢的部分(对public static string ToDecimalString(this BigInteger value)
{
if (value == 0) return "0";
var digits = 10000;
var divider = BigInteger.Pow(10, digits);
var parts = new Stack<string>();
while (true)
{
BigInteger remainder;
value = BigInteger.DivRem(value, divider, out remainder);
if (value != 0)
{
parts.Push(BigInteger.Abs(remainder).ToString().PadLeft(digits, '0'));
}
else
{
parts.Push(remainder.ToString());
break;
}
}
return String.Join("", parts);
}
的调用)无法并行化。
BigInteger.DivRem