Hi,
I am trying to replicate a math problem (for more info see the 4 min video https://www.youtube.com/watch?v=m4CjXk_b8zo)
I am doing a loop for numbers 1 to 10. For each number, if it is even then it becomes number/2, and if it is odd then it becomes 3*number+1. I stop the loop for each number when the number becomes 4, and then I go to the next number.
For each number I want to count how many steps until the number becomes 4.
Here is my code:
data problem;
do i = 1 to 10;
count = 0;
number = i;
do while (number ne 4);
if mod(number,2) = 0 then number = number/2;
else number = 3*number +1;
count = count +1;
output;
end;
end;
run;
I get the result that I want, but the output gives me all the steps for each i. Is it possible to get only the last step for each i?
Thanks!
Strictly speaking, you are right that according to the video the number always reduced to 4 when the process was done in a supercomputer.
To summarize for future readers, the solution is the one given by KSharp. It is basically what I did but the "output" is placed in a different stage which allows to output only the last iteration for each i:
data problem; do i = 1 to 10; count = 0; number = i; do while (number ne 4); if mod(number,2) = 0 then number = number/2; else number = 3*number +1; count = count +1; end; output; end; run;
Please note that the remark of Astounding is very important in that the code can potentally run an infinite loop if for a certain i the number never reaches 4, so in such a case it would be safe to modify the do while statement into a do statement such as "do k=1 to 5000 while (number ne 4);"
This program does what you ask, and write out the numeric sequence for each starting point:
data _null_;
do I=1 to 10;
count=0;
put "Start=" I @;
do N=I by 0 until (N=4);
if mod(N,2)=0 then N=N/2;
else N=1+3*N;
put +(-1)',' N @;
count+1;
end;
put +3 count=;
end;
run;
Sorry - misread your post. I think you want the next_to_last value of N before N=4, and as you said you don't want the sequence:
data want (keep=START next_to_last count);
do START=1 to 10;
count=0;
do N=START by 0 until (N=4);
if mod(N,2)=0 then N=N/2;
else N=1+3*N;
count+1;
next_to_last=coalesce(lag(n),start);
end;
put start= count= next_to_last=;
output;
end;
run;
Hi mkeintz,
thanks for the code, I didn't know that so much computation can be done with PUT.
Your first code does actually give the result that my code gets, its just that I want to have the last (and not before last) iteration for each i.
Thanks!
You already got the right suggestion, moving the OUTPUT statement. Here's one more, just on general principles.
Your DO WHILE loop is dangerous. What if the logic never arrives at NUMBER=4? In theory, at least, you could be writing an infinite loop. It would be safer to have two ways that the loop might end, such as:
do k=1 to 5000 while (number ne 4);
It's not dangerous in this case. According to the youtube videa every starting number up to 2**60 has been test and will ultimately arrive at 1 (and the next step would be 4).
MK
Don't take this seriously, but ...
You heard it on the internet, so it must be true?
In the case of this video,which reviewed the history of this problem, I am confident of the assertion - even though it was reported on the internet.
MK
Strictly speaking, you are right that according to the video the number always reduced to 4 when the process was done in a supercomputer.
To summarize for future readers, the solution is the one given by KSharp. It is basically what I did but the "output" is placed in a different stage which allows to output only the last iteration for each i:
data problem; do i = 1 to 10; count = 0; number = i; do while (number ne 4); if mod(number,2) = 0 then number = number/2; else number = 3*number +1; count = count +1; end; output; end; run;
Please note that the remark of Astounding is very important in that the code can potentally run an infinite loop if for a certain i the number never reaches 4, so in such a case it would be safe to modify the do while statement into a do statement such as "do k=1 to 5000 while (number ne 4);"
I like idea of @Astounding . Safety first. If any problem occurred in the code of LOOP ,that would lead to infinite iterative, you have to stop sas session by hand, that doesn't sound good .
data problem;
do i = 1 to 10;
count = 0;
number = i;
do while (number ne 4);
if mod(number,2) = 0 then number = number/2;
else number = 3*number +1;
count = count +1;
end;
output;
end;
run;
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.