Calculating a recursive sequence iteratively - code optimization - iteration

I have to calculate first 3000 items of a sequence given as follows:
a_1=1,
a_n+1 = smallest integer > a_n, for which for every (not necessarily different) 1<= i,j,k <= n+1 applies (a_i+a_j not equal 3*a_k)
I have written code (in Magma) that works correctly, but its time complexity is obviously way too large. I am asking if there is a way to reduce the time complexity. I had an idea to somehow move the inner for loop (which is the one causing havoc) out in a way of making an array of all the sums, but I cant get it to work right. Attaching my code below:
S:=[1];
for n:=2 to 3000 do
new:=S[n-1];
repeat
flag:=0;
new+:=1;
for i,j in S do
if (i+j eq 3*new) or (i+new eq 3*j) then
flag:=1;
break i;
end if;
end for;
until flag eq 0;
S[n]:=new;
end for;
print S[2015];
P.S.: If it helps, I also know Python, Pascal and C if you prefer any of those languages.

I copied your program in MAGMA. Run time for n=2978 was 4712.766 seconds. I changed your program as follow and result was amazing. Run time for changed version for n=3000 was 41.250 seconds.
S:=[1];
for n:=2 to 3000 do
new:=S[n-1];
repeat
flag:=0;
new+:=1;
for i in S do
if ((3*new-i) in S) or ((i+new)/3 in S) then
flag:=1;
break i;
end if;
end for;
until flag eq 0;
S[n]:=new;
end for;

Related

How the complexity of the following code is O(nlogn)?

for(i=1;i<=n;i=i*2)
{
for(j=1;j<=i;j++)
{
}
}
How the complexity of the following code is O(nlogn) ?
Time complexity in terms of what? If you want to know how many inner loop operations the algorithm performs, it is not O(n log n). If you want to take into account also the arithmetic operations, then see further below. If you literally are to plug in that code into a programming language, chances are the compiler will notice that your code does nothing and optimise the loop away, resulting in constant O(1) time complexity. But only based on what you've given us, I would interpret it as time complexity in terms of whatever might be inside the inner loop, not counting arithmetic operations of the loops themselves. If so:
Consider an iteration of your inner loop a constant-time operation, then we just need to count how many iterations the inner loop will make.
You will find that it will make
1 + 2 + 4 + 8 + ... + n
iterations, if n is a square number. If it is not square, it will stop a bit sooner, but this will be our upper limit.
We can write this more generally as
the sum of 2i where i ranges from 0 to log2n.
Now, if you do the math, e.g. using the formula for geometric sums, you will find that this sum equals
2n - 1.
So we have a time complexity of O(2n - 1) = O(n), if we don't take the arithmetic operations of the loops into account.
If you wish to verify this experimentally, the best way is to write code that counts how many times the inner loop runs. In javascript, you could write it like this:
function f(n) {
let c = 0;
for(i=1;i<=n;i=i*2) {
for(j=1;j<=i;j++) {
++c;
}
}
console.log(c);
}
f(2);
f(4);
f(32);
f(1024);
f(1 << 20);
If you do want to take the arithmetic operations into account, then it depends a bit on your assumptions but you can indeed get some logarithmic coefficients to account for. It depends on how you formulate the question and how you define an operation.
First, we need to estimate number of high-level operations executed for different n. In this case the inner loop is an operation that you want to count, if I understood the question right.
If it is difficult, you may automate it. I used Matlab for example code since there was no tag for specific language. Testing code will look like this:
% Reasonable amount of input elements placed in array, change it to fit your needs
x = 1:1:100;
% Plot linear function
plot(x,x,'DisplayName','O(n)', 'LineWidth', 2);
hold on;
% Plot n*log(n) function
plot(x, x.*log(x), 'DisplayName','O(nln(n))','LineWidth', 2);
hold on;
% Apply our function to each element of x
measured = arrayfun(#(v) test(v),x);
% Plot number of high level operations performed by our function for each element of x
plot(x,measured, 'DisplayName','Measured','LineWidth', 2);
legend
% Our function
function k = test(n)
% Counter for operations
k = 0;
% Outer loop, same as for(i=1;i<=n;i=i*2)
i = 1;
while i < n
% Inner loop
for j=1:1:i
% Count operations
k=k+1;
end
i = i*2;
end
end
And the result will look like
Our complexity is worse than linear but not worse than O(nlogn), so we choose O(nlogn) as an upper bound.
Furthermore the upper bound should be:
O(n*log2(n))
The worst case is n being in 2^x. x€real numbers
The inner loop is evaluated n times, the outer loop log2 (logarithm basis 2) times.

How to calculate the sum of all the odd numbers less than 1000 using a for loop in Xcode (Objective C)

I'm very new to programming and I have no idea where to start, just looking for some help with this, I know its very simple but I'm clueless, thanks for the help!
So this is the code I have:
NSInteger sum = 0;
for (int a = 1; a < 500; a++) {
sum += (a * 2 - 1); }
NSLog(#"The sum of all the odd numbers within the range = %ld",(long)sum);
but I'm getting a answer of 249,001, but it should be 250,000
Appreciate the help!
Your immediate problem is that you're missing a term in the sum: your output differs from the actual answer by 999. This ought to motivate you to write a <= 500 instead as the stopping condition in the for loop.
But, in reality, you would not use a for loop for this as there is an alternative that's much cheaper computationally speaking.
Note that this is an arithmetic progression and there is therefore a closed-form solution to this. That is, you can get the answer out in O(1) rather than by using a loop which would be O(n); i.e. the compute time grows linearly with the number of terms that you want.
Recognising that there are 500 odd numbers in your range, you can use
n * (2 * a + (n - 1) * d) / 2
to compute this. In your case, n is 500. d (the difference between the terms) is 2. a (the first term) is 1.
See https://en.wikipedia.org/wiki/Arithmetic_progression

Function call faster than on the fly calculation?

I am now seriously confused. I have a function creating a table with a random number of entries, and I tried two different methods to choose that number (which is somewhat wheighted):
Method 1, separated function
local function n()
local n = math.random()
if n < .7 then return 0
elseif n < .8 then return 1
end
return 2
end
local function final()
for i = 1, n() do
...
end
end
Method 2, direct calculation
local function final()
local n = math.random()
if n < .7 then n = 0
elseif n < .8 then n = 1
else n = 2
end
for i = 1, n do
...
end
end
The problem is: for some reason, the first method performs 30% faster than the second. Why is this?
No, call will never be faster than plainly inlining it. All the difference for the first method is adding extra work of setting up stack and dismantling it. The rest of code, both original and compiled is exactly the same, so it is only natural that "just calculation" will be faster than "just calculation + some extra work".
Your benchmark seem to be imprecise. For such a lightweight function a for loop and os.clock call themselves will take almost as many time as the function itself, so combined with os.clock inherent low resoulution and small amount of loops your data is not really statistically significant and you're mostly seeing results of random hiccups in your hardware. Use better timer and increase number of loops to at least 1000000.

A loop in fortran code doesn't obey loop rules

First of all i am new at fortran. I tried to find the value of 1/e within tolerance of 0.0000005. I used the summation representation of 1/e which is (epsilon) n from zero goes to infinity ((-1)^n)/n!. I started from n=2 and when the value of 1/n! is smaller than my tolerance, the program will stop and print the total value that is calculated. But my program just goes to n=3 only and only prints the value of 1/3! which is 1.666666.
!program is edited. the edited form is calculates what i wanted.Before the condition of outer while was (num3<5e-8) and it didn't increase n. Now n increases problem is solved.
program Ecalculator
implicit none
integer :: mult,num1,n,num4,num5
real :: summ,num3,fact
mult=1
n=2.0
fact=1.0
summ=0.0
DO WHiLE(n<13)
fact=n
num1=n-1
DO WHiLE(num1>0)
fact=fact*num1;
num1=num1-1;
END DO
fact=fact*mult;
num3=1.0/fact;
mult=mult*(-1);
summ=summ+num3;
n=n+1;
END DO
print *, summ
read *, num5
end program Ecalculator
It looks like the factorial is not computed correctly: the line fact=num4*num1 is probably not doing what you want, because num4 is just assigned to be n and never changes throughout the inner loop. I don't think you need both variables num4 and fact; you could combine them into one variable.

Maple Sequence Length

I'm trying to create a basic program in Maple that runs the Collatz sequence when given a number (n) from the user. For those that don't know, the Collatz sequence is basically "If the number given is odd, do 3n + 1, if it is even, divide by 2 and continue to do so for every answer. Eventually, the answer will reach 1"
I'm trying to grab the number of iterations that the sequence is performed, say if the sequence is run through 10 times, it prints that out. Here is my current code:
Collatz := proc (n::posint)
if type(n, even) then (1/2)*n
else 3*n+1
end if
end proc
CollSeq := proc (n::posint)
local i;
i := n;
while 1 < i do
lprint(i);
i := Collatz(i)
end do
end proc
This so far works, and if the proc CollSeq(50) is entered, it will perform the Collatz sequence on 50 until it reaches 1. The bit I am stuck on is the length of the sequence. I have read around and learned that I might be able to use the nops([]) function of Maple to get the length of the sequence. Here is what I have tried:
CollLen := proc (n::posint)
local c;
c := CollSeq(n);
print(nops([c]))
end proc
I have a feeling this is horribly wrong. Any help would be much appreciated.
Many Thanks
Your function fails to return the actual sequence of values. You need to accumulate it as you go through the loop.
CollSeq := proc (n::posint)
local i, s;
i := n;
s := i;
while 1 < i do
lprint(i);
i := Collatz(i);
s := s, i;
end do;
s;
end proc
The lprint() command just prints its argument to the terminal (showing it on screen), it DOES not save it in a list. And nops() or a better command numelems() counts the number of elements in a list! So putting nops around something that has lprint will not count the number of things. Instead of using lprint in your second function (procedure), define a list, or better than list, an array and in the lprint-line, use a command to append the new number to your growing collection. If you want to see these numbers, just print this collection. Now this time, your third function can have a meaning and it will work as you expected.
Here is the closest fix to your codes.
Collatz := proc( n :: posint )
if type(n, even) then
return( n/2 ):
else
return( 3*n+1 ):
end if:
end proc:
CollSeq := proc ( n :: posint )
local
i :: posint,
c :: 'Array'( posint ):
i := n:
c := Array([]):
while 1 < i do
ArrayTools:-Append( c, i ):
i := Collatz( i ):
end do:
return( c ):
end proc:
CollLen := proc ( n :: posint )
local c :: posint:
c := CollSeq( n ):
return( numelems( c ) ):
end proc:
Here is a screenshot of using them in a Maple worksheet.
Why do I use an array and not a list? Because if you use a list which is immutable, each time you want to add an element to it, in fact it is defining a new list. It is not a memory efficient way, while array is mutable and your edits modifies the array itself. See the help pages on these in Maple.
And looking at your codes, it seems you have the same problem that some of my students in their first programming course usually have, return and print are not the same thing. If you really want a "print" action, that is fine, but you should not expect that the printed value be the output of the function unless you are using a return line inside the function that returns the same value of the print as well. For example you can have print(c): before return(c): in the second function above. So it both prints the sequence on the terminal and returns it to be used by another function or line of code.