简体   繁体   中英

How could I approach N times sum of 3 numbers?

More detail about the problem, I had the task to program the sequence 1 2 3 and the sum of the last 3 numbers N times, so it would be like 1 2 3 6 11 20 37. I approached it like this

static void Main()
        {
            BigInteger cont;
            BigInteger MAX = 2020202020202020;
            BigInteger[] Numberstrack = { 1, 2, 3 };
            BigInteger sum = 0;
            for (cont = 3; cont < MAX; cont++)
            {
                sum = Numberstrack[0] + Numberstrack[1] + Numberstrack[2];
                Numberstrack[0] = Numberstrack[1];
                Numberstrack[1] = Numberstrack[2];
                Numberstrack[2] = sum;
                Console.WriteLine(cont);//just to know how much is it going and how fast
            }
            Console.WriteLine("Numero " + cont + ": " + sum.ToString().Substring(sum.ToString().Length - 4));
        }

You can see the number I need to get is absurd large but that's why I wanna know, if someone know about other way to approach this problem and probably not to wait for 1+ hour to get the result.

PD : If you ask, why I started in cont 3, its because this sequence starts really with [0, 1, 0] and a clue in the problem was that the 30th position was the 45152016.

PD2: I had to use System.Numerics.BigInteger to handle the big numbers. Thanks all and have a nice day.

For i-th number we have:

A(i-1)*2-a(i-4)

I is greater than 4 becuz we must have the first 4 numbers.

@amk was on the right lines, but you need to increase your elements to 4.

I did a series of experiments gradually optimising the code. By way of warning I only ran 5 tries of 300,000 iterations, simply because I did not want to chew up my PC all day. I advise you to repeat my tests yourself.

Firstly I ran your code as is: I got an average of 8,310 milliseconds.

Next I replaced your BigInteger[] with three variables, a, b and c. This brought a small (expected) gain, with an average run of 8,214 milliseconds.

Now I tried a variant of @amk, but with the required 4 variables, and also with running the iteration in batches of four. This got the average down to 7,768 milliseconds.

Finally I replaced the multiplication by 2 with a left shift, leaving me with a final average of 7,247 milliseconds, ie over a second faster than the original.

My last code looks like this:

static void leftShift()
{
    BigInteger cont;
    BigInteger MAX = 300000;
    BigInteger a = 1;
    BigInteger b = 2;
    BigInteger c = 3;
    BigInteger d = 6;

    BigInteger sum = 0;
    for (cont = 4; cont < (MAX - 3); cont += 4)
    {
        a = (d << 1) - a;
        b = (a << 1) - b;
        c = (b << 1) - c;
        d = (c << 1) - d;
    }
    sum = d;
    if (cont < MAX)
    {
        a = (d << 1) - a;
        sum = a;
        cont++;
    }
    if (cont < MAX)
    {
        b = (a << 1) - b;
        sum = b;
        cont++;
    }
    if (cont < MAX)
    {
        c = (b << 1) - c;
        sum = c;
        cont++;
    }
    Console.WriteLine("Numero " + cont + ": " + sum.ToString());
}

I only wrote to the Console at the end of the operation, plus a separate print of the time taken.

In my case (using 300,000) I did not need the extra tests at the end, since 300,000 is exactly divisible by 4, but I put them in for completeness' sake in case a MAX is used that is not so convenient!

As a final aside, what was particularly interesting, was that with each optimisation the standard deviation of my results fell dramatically (818.7, 485.7, 129.4 and finally 38.2). I am sure that one of the experts here can explain that. To the mind of a mere mortal, though, it does confirm to me that my optimisations were also theoretically sound (as well as a practical improvement).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM