Reputation: 33
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
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