¿La forma más rápida de convertir un BigInteger en una cadena decimal (Base 10)?

Respuestas hasta ahora

Así que aquí está el código desglosado.

//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
Materia original de la pregunta

He gastado demasiado tiempo en esto, por lo que necesito su ayuda.

Esto es para un proyecto personal para calcular factoriales descomunales (por ejemplo, ¡100.000!)

Aquí está mi código:

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);

¡En 100,000! Esto toma aproximadamente 7 segundos en mi máquina para calcular (algoritmo de bucle lineal).

Sin embargo, con este código de E / S estándar se necesitan 13 segundos para guardar.

Entonces, en otras palabras, se necesita más tiempo para guardar el trabajo que para computarlo modestamente.

Así que pensé que tal vez podría usar:

BigInteger.ToByteArray();

Aunque esto funciona extremadamente rápido,No pude averiguar cómo guardarlo en texto legible.

Puede usar el método anterior para escribir la cadena binaria en un archivo de texto con esta extensión de creación propia:

ToBinaryString
//Usage: string bigIntBinary = bigIntVar.ToBinaryString();
public static string ToBinaryString(this BigInteger source)
{
    //If you lookup the ToByteArray() method...
    //It actually stores the bytes in reverse order.
    var bigIntBytes = source.ToByteArray().Reverse();

    StringBuilder bigIntBinary = new StringBuilder();

    foreach (var bigIntByte in bigIntBytes)
    {
       bigIntBinary.Append(Convert.ToString(bigIntByte, 2).PadLeft(8, '0'));
    }

    return bigIntBinary.ToString();
}
ToBase64String
    ////Usage: string bigIntBase64 = bigIntVar.ToBase64String();
    public static string ToBase64String(this BigInteger source)
    {
        var bigIntBytes = source.ToByteArray().Reverse().ToArray();

        return Convert.ToBase64String(bigIntBytes);
    }

También probé el método matemático (mod 10, etc ...) para obtener cada dígito, pero eso lleva un TON más tiempo que ToString ().

¿Qué estoy haciendo mal aquí?

Este código es el que encontré basado en la respuesta a continuación. Esto es más rápido que ToString (), pero solo por un par de segundos.

ToQuickString
//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);
}

Respuestas a la pregunta(2)

Su respuesta a la pregunta