Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8801271
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 14, 20262026-06-14T00:47:31+00:00 2026-06-14T00:47:31+00:00

Answers So Far So here is the code breakdown. //Time: ~7s (linear loop algorithm)

  • 0

Answers So Far

So here is the code breakdown.

//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

Original Question Stuff

I have spent way to much time on this, so I need your help.

This is for a personal project to compute ginormous factorials (ex. 100,000!)

Here is my code:

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

On 100,000! is takes about 7sec on my machine to compute (linear loop algorithm).

Yet with this standard IO code it takes 13sec to save.

So in other words, it takes longer to save the work than it does to modestly compute it.

So I thought maybe I could use:

BigInteger.ToByteArray();

Although this runs extremely fast, I couldn’t figure out how to save it to readable text.

You can use the above method to write the binary string to a text file with this self-made extension:

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

I also tried the math way (mod 10, etc…) to get each digit, but that takes a TON more time that ToString().

What am I doing wrong here?


This code is what I came up with based on the answer below.
This is faster than ToString(), but only by a couple seconds.

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);
}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-14T00:47:32+00:00Added an answer on June 14, 2026 at 12:47 am

    Save the BigInteger data in binary or hex format. It is readable to the computer, and to sufficiently dedicated humans. ;>

    Spending extra effort to make the output “human readable” is a waste of time. No human is going to be able to make sense out of 450,000 digits regardless of whether they are base 10, base 16, base 2, or anything else.

    UPDATE

    Looking into the Base 10 conversion a little more closely, it is possible to cut the baseline performance of ToString almost in half using multiple threads on a multi core system. The main obstacle is that the largest consumer of time across the entire decimalization process is the first division operation on the original 450k digit number.

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

    For ToQuickString() and ToStringMT(), the powers of 10 array needs to be initialized prior to using these functions. Initializing this array shouldn’t be included in function execution time measurements because the array can be reused across subsequent calls, so its initialization cost is amortized over the lifetime of the program, not individual function calls.

    For a production system I would set up a more automatic initialization, such as initializing a reasonable number of entries in the class static constructor and then checking in ToQuickString() or ToStringMT() to see if there are enough entries in the table to handle the given BigInteger. If not, go add enough entries to the table to handle the current BigInteger, then continue with the operation.

    This ToStringMT function constructs the worker tasks manually to spread the remaining work out across 4 threads on the available execution cores in a multi core CPU. You could instead just make the original ToQuickString() function spin off half of its work into another thread on each recursion, but this quickly creates too many tasks and gets bogged down in task scheduling overhead. The recursion drills all the way down to individual decimal digits. I modified the BuildString() function to bail out earlier (m <= 8 instead of m == 0) because BigInteger.ToString() is faster than DivRem for smallish numbers.

    90% of ToStringMt()’s execution time is taken up by the first DivRem call. It converges very quickly after that, but the first one is really painful.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I post this previously in Adobe Forum but haven't got any answers so far.
Why new()/delete() is slower than malloc()/free()? EDIT: Thanks for the answers so far. Please
I've seen many answers here in Stack Overflow explaining how we can remove the
I'm one of those guys who come here to find answers to those questions
My code is working so far but I had to create a Class for
Can someone explain to me the syntax of the For loop in Firebird? Here
Here's the code in question: #!/usr/bin/python import pycurl c = pycurl.Curl() values = [
THE EXAMPLE First and foremost, here's my code and problem: http://www.nathanstpierre.com/MBX/showoff.html THE ISSUE So
The answers I've found to this question (such as here , here , and
myfile.log contains things like: ----- 12:08:12 (123.123.123.123) -------------------------------- Some code here... This section has

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.