有效地将大型BigInteger转换为字符串,ToString()花费的时间太长

时间:2019-05-11 08:00:34

标签: c#

我正在处理阶乘函数,具有大整数的阶乘会变得很长。

例如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

2 个答案:

答案 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 calculationbigint 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