x86 machine code, 15 bytes
xxd -g1:
00000000: 99 42 8d 4c 40 01 d1 e8 0f 42 c1 75 f4 4a c3 [email protected].
Commented assembly (NASM syntax):
[bits 32]
global collatz
; input: eax, assumed positive and > 1
; output: edx
; clobbers: eax, ecx, edx
collatz:
cdq ; count = 0 (abuses eax > 1)
.Lloop:
inc edx ; increment count
lea ecx, [eax+2*eax+1] ; tmp = 3*n + 1
shr eax, 1 ; n = n / 2, sets flags
cmovc eax, ecx ; swap with 3n+1 if it was originally odd (does not set flags)
jnz .Lloop ; shr also sets ZF if the shr result was zero, end condition
dec edx ; Correct the off by one
ret ; return
Try it online! (converted to GAS Intel syntax and wrapped in C++)
Notes
The way this works is by using shr
magic, allowing me to calculate n/2
and also test if n
was originally odd (CF=1
) or originally 1
(ZF=1
).
Unfortunately, this results in an off by one since it will run when n == 1
, but it is correctable via a simple dec
.
Note that while this is larger than the other x86 solution, the other solution is a snippet, not a complete function, and it doesn't even count the steps, only calculating the sequence.
If that version were to count the steps, while it would be more efficient, it would be larger because the bsr
complicates the bookkeeping, unless I can be proven otherwise.