Problem overview
The function printSeries receives an integer n and prints every value that n takes in the Collatz sequence. The rule is applied again and again: if the current number is even, the next one is half of it; if it is odd, the next one is three times it plus one. The sequence stops when it reaches 1, which every starting number tried so far eventually does, though nobody has proved that it always happens.
For n = 3 the output is one number per line: 3, 10, 5, 16, 8, 4, 2, 1. The starting value is printed first, then each new value as it is produced.
Approach: repeat a rule until a stopping value
The number of steps isn't known in advance, so a loop with a fixed count doesn't fit. The right tool is a loop that repeats while a condition holds: here, while n is greater than 1. Inside the loop, one step applies the even or odd rule to n and prints the new value.
The first value, the starting n, is printed before the loop. That way the output starts with the input and ends with the 1 that stops the loop. If n is already 1, the condition is false from the start, so the output is just 1.
Step by step
- Print the starting value with
fmt.Println(n). This is the first term of the series. - Write the loop. Go has no
whilekeyword; aforwith only a condition does the same job.for n > 1 { ... }repeats as long asnis greater than 1. - Handle the even case. Inside the loop, an
iftests whethern % 2 == 0. If so, halven. The parameternis an ordinary local variable, so the function can change it directly. - Handle the odd case. The
elsebranch runs exactly whennis odd. It setsnto3 * n + 1. - Print the new value after the
if/else, still inside the loop. Placed there, one print covers both branches.
The solution in Go
func printSeries(n int) {
fmt.Println(n)
for n > 1 {
if n % 2 == 0 {
n /= 2
} else {
n = 3 * n + 1
}
fmt.Println(n)
}
}
Tracing n = 6 through the code gives 6, 3, 10, 5, 16, 8, 4, 2, 1: the first print outputs 6, then each pass of the loop moves to the next term and prints it.
Go details:
foris the only loop. Aforwith just a condition is Go'swhile. A barefor { }loops forever until abreakorreturn.- Integer division truncates.
/between twointvalues drops the remainder. Here it is applied only to even numbers, so nothing is lost. - Compound assignment.
n /= 2meansn = n / 2. Go also has+=,-=,*=and%=. - Parameters are copies. Changing
ninside the function doesn't affect the caller's variable, because Go passes arguments by value. - Braces on the same line. The opening brace of
for,ifandelsemust be on the same line as the keyword, andelsemust follow the closing brace:} else {.
Complexity
There is no simple formula for the number of steps. The sequence can rise before it falls: starting from 27, it takes 111 steps and climbs far above 27 before dropping to 1. So the running time depends on the input in an irregular way. Nobody has proved that the loop ends for every positive input, though it has been checked for enormous ranges of starting values. The space is O(1), since the function keeps only n.
Edge cases and common mistakes
- n = 1. The function prints
1and the loop never runs. - Powers of two.
n = 8prints 8, 4, 2, 1, because each step halves the number. - Forgetting the first print. The output would start from the second term, 10, for an input of 3.
- Printing before the update. If the print is first in the loop, the final 1 is never printed, because the loop ends before the print can run.
- Printing inside only one branch. Every term must appear, whether it was produced by the even rule or the odd rule.
- Zero or negative input. The condition
n > 1is false, so onlynis printed. The problem only considers positive integers. - Using
if n % 2 == 1for the odd test. That works for positive numbers, but for negative ones%gives -1, soelseis the safer choice.
Testing
printSeries(3)prints 3, 10, 5, 16, 8, 4, 2, 1, one per line.printSeries(1)prints 1.printSeries(6)prints 6, 3, 10, 5, 16, 8, 4, 2, 1.