Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将BigInteger转换为十进制(以10为基数)字符串的最快方法? 迄今为止的答案_C#_Tostring_Biginteger - Fatal编程技术网

C# 将BigInteger转换为十进制(以10为基数)字符串的最快方法? 迄今为止的答案

C# 将BigInteger转换为十进制(以10为基数)字符串的最快方法? 迄今为止的答案,c#,tostring,biginteger,C#,Tostring,Biginteger,下面是代码分解 //Time: ~7s (linear loop algorithm) //100,000! (456,574 decimal digits) BigInteger bigIntVar = computeFactorial(100000); //The first three here are just for comparison and are not actually Base 10. bigIntVar.ToBase64String() //Time: 00.001s

下面是代码分解

//Time: ~7s (linear loop algorithm)
//100,000! (456,574 decimal digits)
BigInteger bigIntVar = computeFactorial(100000);

//The first three here are just for comparison and are not actually Base 10.
bigIntVar.ToBase64String() //Time: 00.001s | Base 64 | Tetrasexagesimal
bigIntVar.ToString("x")    //Time: 00.016s | Base 16 | Hexadecimal
bigIntVar.ToBinaryString() //Time: 00.026s | Base 02 | Binary
bigIntVar.ToQuickString()  //Time: 11.200s | Base 10 | String Version
bigIntVar.ToQuickString()  //Time: 12.500s | Base 10 | StringBuilder Version
bigIntVar.ToString()       //Time: 13.300s | Base 10 | Original

原始问题材料 我在这件事上花了很多时间,所以我需要你的帮助

这是一个计算ginormous阶乘的个人项目(例如100000!)

这是我的密码:

using (var stream = new StreamWriter(fileName + ".txt", false))
{
    stream.WriteLine(header);

    var timer = new Stopwatch();    
    timer.Restart();
    //This is the huge BigInteger holding the answer to 100,000!
    stream.WriteLine(saveFactorial.Output.ToString());         
    //Let me be clear: ToString() is directly causing the the 13sec time delay.
    //Not the stream.
    timer.Stop();                   
}

time = (timer.ElapsedMilliseconds / 1000.0).ToString() + "s"; 

MessageBox.Show(time);
10万!在我的机器上计算大约需要7秒(线性循环算法)

然而,使用此标准IO代码需要13秒才能保存

因此,换句话说,节省工作量所需的时间比适度计算所需的时间更长

所以我想也许我可以用:

BigInteger.ToByteArray();
虽然运行速度非常快,但我不知道如何将其保存为可读文本

您可以使用上述方法将二进制字符串写入具有此自制扩展名的文本文件:

ToBinaryString Tobase64字符串 我还尝试了数学方法(mod 10等)来获取每个数字,但这比ToString()要花费更多的时间

我做错了什么


这是我根据下面的答案得出的代码。 这比ToString()快,但只需几秒钟

快速串
//用法:string bigIntString=bigIntVar.ToQuickString()
公共静态字符串到QuickString(此BigInteger源)
{
powersforment=新列表();
增加(1);
对于(大整数i=10;i
首先,我要计算小于
n的
10^(2^m)
表格中的所有数字。然后我将使用
DivRem
和其中最大的一个来将问题分成两个子问题。递归地重复这个过程,直到你只剩下一个数字

var powersOfTen=new List<BigInteger>();
powersOfTen.Add(1);
for(BigInteger i=10;i<n;i=i*i)
  powersOfTen.Add(i);

string ToString(BigInteger n, int m)
{
  if(m==0)
    return n.ToString();
  quotient = DivRem(n,powersOfTen[m], remainder)
  return ToString(quotient, m-1)+ToString(remainder, m-1)
}
var powersforment=new List();
增加(1);

对于(BigInteger i=10;i以二进制或十六进制格式保存BigInteger数据。计算机和足够专业的人员都可以读取该数据。>

花费额外的精力使输出“人类可读”是浪费时间。没有人能够理解450000位数字,无论它们是以10为基数、以16为基数、以2为基数还是其他任何数字

更新 更仔细地看一下基数10转换,在多核系统上使用多个线程可能会将ToString的基线性能降低近一半。主要障碍是整个十进制过程中最大的时间消耗是对原始450k位数的第一次除法运算

公共静态类BigIntExtensions
{
私有静态列表;
//必须在ToString()之前调用
公共静态void initpowersforment(BigInteger n)
{
powersforment=新列表();
增加(1);
对于(大整数i=10;i
{
大整数r1r2;
biginger r1q2=biginger.DivRem(r1,biginextensions.powersforment[m-1],out r1r2);
var t2=Task.Factory.StartNew(()=>BuildString(r1r2,m-2));
返回BuildString(r1q2,m-2)+t2.Result;
});
大整数q1r2;
BigInteger q1q2=BigInteger.DivRem(q1,BigIntExtensions.PowerStory[m-1],out q1r2);
var t3=Task.Factory.StartNew(()=>BuildString(q1r2,m-2));
var sb=新的StringBuilder();
sb.Append(BuildString(q1q2,m-2));
sb.追加(t3.结果);
sb.追加(t1.结果);
使某人返回字符串();
}
//与ToQuickString相同,但在m==0之前退出以减少调用开销。
//对于较小的数字,biginger.ToString()比DivRem快。
私有静态字符串BuildString(biginger n,int m)
{

if(m)调用
ToString
似乎需要相当长的时间,但如果您希望该文件具有人类可读性,则对此无能为力。是的,我进行了编辑以澄清这一点。我对其进行了相当长时间的调试,发现ToString()没有其他原因造成时间延迟。没有更快的方法将大整数转换为字符串吗?我怀疑。你真的需要这些让人可读吗?没有人会坐下来读一个450k字符的数字,是吗?我有一个1GB的文本文件,有10亿位Pi…这更像是个人的事情。我只是想知道至少,我有一个450k的数字,这在我的计算机上意味着一些东西。哈,这很公平:)如果文件是可读的十六进制文件,那么它对你来说也意味着相同的话,调用
.ToString(“x”)
快得多。快去把它加入书签并试用。不过现在需要一些睡觉时间。我真的很喜欢这个主意。虽然递归可能会导致堆栈溢出,因为有450k个数字。不,它不会导致堆栈溢出。递归深度是对数位数。刚刚测试了这个代码。让我来看看知道我是否实现了这个错误。我不认为我做了。我没有时间去做“正确”的代码。这只是你做的一个快速复制。我只是想补充一下,目前它正在放置所有
    ////Usage: string bigIntBase64 = bigIntVar.ToBase64String();
    public static string ToBase64String(this BigInteger source)
    {
        var bigIntBytes = source.ToByteArray().Reverse().ToArray();

        return Convert.ToBase64String(bigIntBytes);
    }
//Usage: string bigIntString = bigIntVar.ToQuickString()
public static String ToQuickString(this BigInteger source)
{
    powersOfTen = new List<BigInteger>();

    powersOfTen.Add(1);

    for (BigInteger i = 10; i < source; i *= i)
    {
        powersOfTen.Add(i);
    }

    return BuildString(source, powersOfTen.Count - 1).ToString().TrimStart('0');
}

private static List<BigInteger> powersOfTen;

private static string BuildString(BigInteger n, int m)
{
    if (m == 0)
        return n.ToString();

    BigInteger remainder;
    BigInteger quotient = BigInteger.DivRem(n, powersOfTen[m], out remainder);

    return BuildString(quotient, m - 1) + BuildString(remainder, m - 1);
}
var powersOfTen=new List<BigInteger>();
powersOfTen.Add(1);
for(BigInteger i=10;i<n;i=i*i)
  powersOfTen.Add(i);

string ToString(BigInteger n, int m)
{
  if(m==0)
    return n.ToString();
  quotient = DivRem(n,powersOfTen[m], remainder)
  return ToString(quotient, m-1)+ToString(remainder, m-1)
}
List<int> multiply(List<int> f1, int f2)
{
  int carry=0;
  for(int i=0;i<f1.Count;i++)
  {
    var product=(Int64)f1[i]*(Int64)f2;
    carry=product/1000000000;
    result.Add(product%1000000000);
  }
  if(carry!=0)
    result.Add(carry);
}
Stats on my quad core P7: 
Generating a 500k digit random number using power and multiply: 5 seconds
Dividing that big number by anything just once: 11 seconds
ToString(): 22 seconds
ToQuickString: 18 seconds
ToStringMT: 12.9 seconds
public static class BigIntExtensions
{
    private static List<BigInteger> powersOfTen;

    // Must be called before ToStringMt()
    public static void InitPowersOfTen(BigInteger n)
    {
        powersOfTen = new List<BigInteger>();

        powersOfTen.Add(1);

        for (BigInteger i = 10; i < n; i *= i)
            powersOfTen.Add(i);
    }

    public static string ToStringMT(this BigInteger n)
    {
        // compute the index into the powersOfTen table for the given parameter. This is very fast.
        var m = (int)Math.Ceiling(Math.Log(BigInteger.Log10(n), 2));

        BigInteger r1;
        // the largest amount of execution time happens right here:
        BigInteger q1 = BigInteger.DivRem(n, BigIntExtensions.powersOfTen[m], out r1);

        // split the remaining work across 4 threads - 3 new threads plus the current thread
        var t1 = Task.Factory.StartNew<string>(() =>
        {
            BigInteger r1r2;
            BigInteger r1q2 = BigInteger.DivRem(r1, BigIntExtensions.powersOfTen[m - 1], out r1r2);
            var t2 = Task.Factory.StartNew<string>(() => BuildString(r1r2, m - 2));
            return BuildString(r1q2, m - 2) + t2.Result;
        });
        BigInteger q1r2;
        BigInteger q1q2 = BigInteger.DivRem(q1, BigIntExtensions.powersOfTen[m - 1], out q1r2);
        var t3 = Task.Factory.StartNew<string>(() => BuildString(q1r2, m - 2));
        var sb = new StringBuilder();
        sb.Append(BuildString(q1q2, m - 2));
        sb.Append(t3.Result);
        sb.Append(t1.Result);
        return sb.ToString();
    }

    // same as ToQuickString, but bails out before m == 0 to reduce call overhead.
    // BigInteger.ToString() is faster than DivRem for smallish numbers.
    private static string BuildString(BigInteger n, int m)
    {
        if (m <= 8)
            return n.ToString();

        BigInteger remainder;
        BigInteger quotient = BigInteger.DivRem(n, powersOfTen[m], out remainder);
        return BuildString(quotient, m - 1) + BuildString(remainder, m - 1);
    }
}