jdarrell
jdarrell

Reputation: 33

Why does this result in an infinite loop?

I have a simple program that I want to take in a number and iteratively apply one of two rules to bring the number down to 1, all the while keeping track of how many iterations it took to get there.

The rules are simple: (for a positive integer n) n --> n/2 (n is even) n --> 3n+1 (n is odd)

The code I wrote to accomplish this:

class Collatz
  attr_accessor :number, :counter
  def initialize(number)
    @number = number
    @counter = 0
  end

  def collatz
    until (@number == 1) do
      self.hotpo
      @counter += 1
    end
  end

  def hotpo
    @number = self.half if @number.even?
    @number = self.triple_plus_one if @number.odd?
  end

  def half
    @number / 2
  end

  def triple_plus_one
    (3 * @number) + 1
  end
end

num = Collatz.new(13)

puts num.number #==> 13
puts num.counter #==> 0
num.collatz #currently results in infinite loop
puts num.number #should give 1
puts num.counter #should give 9

So for example, if I instantiate the object, passing in 13, @number should change from 13 -> 40 -> 20 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1 and then terminate, but it is currently getting stuck in an infinite loop alternating between @number=2 and @number = 4. How is this happening? Thanks!

Upvotes: 3

Views: 96

Answers (1)

Sergio Tulentsev
Sergio Tulentsev

Reputation: 230551

The problem is that you evaluate @number twice. And modification may also happen twice.

Let's see how it goes when number is 2:

@number = self.half if @number.even?

2 is even, so it is halved. @number is now 1.

But then, the second line executes.

@number = self.triple_plus_one if @number.odd?

@number is now odd, so it becomes 3*1 + 1. You see, poor @number can never stabilize on 1.

To fix that, you need to check the number once. And then make one modification.

def hotpo
  if @number.even?
    @number = half
  else
    @number = triple_plus_one
  end
end

Or a shorter form

def hotpo
  @number = @number.even? ? half : triple_plus_one
end

Upvotes: 5

Related Questions