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.