cint university / 101 / ced, the cint editor
101-08: loops that wait
This is lesson 101-08 of CU-101.2, checked against cint 0.2.0.
You will write a loop that runs until something becomes true, however many passes that takes. You will also stop a loop early or skip a pass.
the program
Here is a rule: if a number is even, halve it; if it is odd, triple it and add one. Start from 27 and repeat until the number reaches 1:
// Halve it if even, triple it and add one if odd, until it reaches 1.
I64 start = 27;
I64 n = start;
I64 steps = 0;
I64 highest = n;
while (n != 1) {
if (n % 2 == 0) {
n = n / 2;
} else {
n = 3 * n + 1;
}
steps += 1;
if (n > highest) { highest = n; }
}
"{start} reaches 1 in {steps} steps, climbing as high as {highest}\n";
Run it:
27 reaches 1 in 111 steps, climbing as high as 9232
The numbers rise and fall like a hailstone in a storm cloud before they come down to 1, which is why the list of numbers is called a hailstone sequence. Every positive whole number anyone has tried comes down to 1 in the end, but nobody has proved that every one does.
what happened
while repeats as long as its condition is true. Before each pass, cint checks n != 1. While it is true, the lines in the braces run again. When n reaches 1, the condition is false and the program goes on to the line after the loop. Nobody knows in advance how many passes that takes: for 27 it is 111. That is the difference from lesson 101-07's for, which counts a set number of passes.
Something inside the loop must change the condition. Each pass changes n. A loop whose condition never becomes false runs until something else stops it.
steps and highest keep a running tally. steps += 1; counts the passes. highest starts at 27, and whenever n climbs above it, highest takes the new value.
A while loop can count down. A for range only counts up, so counting down is a job for while:
I64 n = 5;
while (n > 0) {
"{n}\n";
n -= 1;
}
"liftoff\n";
This prints 5, 4, 3, 2 and 1, one to a line, then liftoff.
stopping early, skipping a pass
break; leaves a loop at once. continue; skips the rest of the current pass and goes on to the next one:
// The first power of 2 above 1000.
I64 x = 1;
while (true) {
x *= 2;
if (x > 1_000) {
break;
}
}
"first power of 2 above 1000: {x}\n";
// The numbers from 1 to 10 that 3 does not divide.
for n in 1..=10 {
if (n % 3 == 0) {
continue;
}
"{n} ";
}
"\n";
first power of 2 above 1000: 1024
1 2 4 5 7 8 10
while (true) would run forever, so the break inside it is the only way out. In the second loop, continue skips the print for 3, 6 and 9.
change it
- Set
startto 7. How many steps does it take, and how high does it climb? - Set
startto 97. Which takes more steps, 27 or 97? - Change the countdown to count down from 10 in twos: 10, 8, 6, 4, 2.
what 7 prints
7 reaches 1 in 16 steps, climbing as high as 52
when it goes wrong
Leave out the halving by mistake, so that every pass triples and adds one:
I64 n = 27;
I64 steps = 0;
while (n != 1) {
n = 3 * n + 1;
steps += 1;
}
n only grows, so it never reaches 1. The same loop written in Python 3.13 ran until it was stopped after 10 seconds, because Python's numbers can grow until the computer runs out of memory. In cint, the number runs out of room on pass 37 and the program stops with a fault:
fault[E_OVERFLOW]: the exact result is outside the type's range
--> runaway.ci:4:11
|
4 | n = 3 * n + 1;
| ^ mul.checked.i64
|
= operation: mul.checked.i64
= operand-count: 2
= operand: I64 3
= operand: I64 4127602470667475827
= exact: 12382807412002427481
= limit: I64 9223372036854775807
...
A loop that starts with a true condition, never changes anything its condition reads and has no break runs forever. To stop a program running in a terminal, press Ctrl+C. To stop one running in the browser, reload the page.