Repeat-until

Collatz Conjecture
Collatz Conjecture in Free Pascal
unit CollatzConjecture;

{$mode ObjFPC}{$H+}

interface

function steps(const number: integer): integer;

implementation

uses SysUtils;

function steps(const number: integer): integer;
var
  temp: integer;
begin
  if number < 1 then
    raise Exception.Create('Only positive integers are allowed');

  temp := number;
  result := 0;
  if temp = 1 then
    exit;
  repeat
    if temp mod 2 <> 0 then begin
      temp := (temp * 3 + 1);
      inc(result);
    end;
    temp := temp div 2;
    inc(result);
  until temp = 1;
end;

end.

This approach uses Pascal's repeat...until loop and exploits the fact that for odd n, 3n + 1 is always even.

The repeat...until loop

Unlike while...do, which checks the condition before each iteration, repeat...until checks the condition after each iteration:

repeat
  ...
until temp = 1;

The repeat and until keywords act as implicit delimiters for the loop body, so there is no need for a begin...end compound statement around the entire loop body. This is different from while...do, which requires begin...end when the body contains more than one statement.

Note that the condition logic is inverted compared to while: instead of continuing while the condition is true, but repeat...until continues until the condition becomes true (that is, it loops while the condition is false).

Guarding against number = 1

Because repeat...until always executes its body at least once, the case where number is already 1 must be handled before entering the loop. The exit statement returns from the function immediately:

if temp = 1 then
  exit;

At this point result is already 0, so exit returns the correct value. The exit procedure leaves the current function, and the value of result at the time of the exit call becomes the return value.

The odd-number shortcut

For any odd number n, the value 3n + 1 is always even. This means the next step after computing 3n + 1 will always be a division by 2.

Using result directly as the counter

Instead of declaring a separate count variable, this approach writes directly to the implicit result variable:

result := 0;
...
inc(result);

This works because result is a fully usable local variable — it can be read, written, and passed to procedures like inc.

23rd Sep 2026 · Found it useful?