Trying to teach myself ruby - I'm working on Project Euler problem 14 in ruby.
n = 1000000
array = Array.new(n,0)
#array[x] will store the number of steps to get to one if a solution has been found and 0 otherwise. x will equal the starting number. array[0] will be nonsensical for these purposes
i = n-1#We will start at array[n-1] and work down to 1
while i > 1
if array[i] == 0
numstep = 0 #numstep will hold the number of loops that j makes until it gets to 1 or a number that has already been solved
j = i
while j > 1 && (array[j] == 0 || array[j] == nil)
case j%2
when 1 # j is odd
j = 3*j + 1
when 0 # j is even
j = j/2
end
numstep += 1
end
stop = array[j] #if j has been solved, array[j] is the number of steps to j = 1. If j = 1, array[j] = 0
j = i
counter = 0
while j > 1 && (array[j] == 0 || array[j] == nil)
if j < n
array[j] = numstep + stop - counter #numstep + stop should equal the solution to the ith number, to get the jth number we subtract counter
end
case j%2
when 1 #j is odd
j = 3*j+1
when 0 #j is even
j = j/2
end
counter += 1
end
end
i = i-1
end
puts("The longest Collatz sequence starting below #{n} starts at #{array.each_with_index.max[1]} and is #{array.max} numbers long")
This code works fine for n = 100000 and below, but when I go up to n = 1000000, it runs for a short while (until j = 999167 *3 + 1 = 2997502). When it tries access the 2997502th index of array, it throws the error
in '[]': bignum too big to convert into 'long' (RangeError)
on line 27 (which is the while statement:
while j > 1 && (array[j] == 0 || array[j] == nil)
How can I get this to not throw an error? Checking if the array is zero saves code efficiency because it allows you to not recalculate something that's already been done, but if I remove the and statement, it runs and gives the correct answer. I'm pretty sure that the problem is that the index of an array can't be a bignum, but maybe there's a way to declare my array such that it can be? I don't much care about the answer itself; I've actually already solved this in C# - just trying to learn ruby, so I'd like to know why my code is doing this (if I'm wrong about why) and how to fix it.
The code above runs happily for me for any input that produces output in acceptable time. I believe this is because you might experience problems being on 32bit arch, or like. Anyway, the solution of the problem stated would be simple (unless you might run out of memory, which is another possible glitch.)
Array indices are limited, as is follows from the error you got. Cool, let’s use hash instead!
n = 1000000
array = Hash.new(0)
#array[x] will store the number of steps to get to one if a solution has been found and 0 otherwise. x will equal the starting number. arr
i = n-1#We will start at array[n-1] and work down to 1
while i > 1
if array[i].zero?
numstep = 0 #numstep will hold the number of loops that j makes until it gets to 1 or a number that has already been solved
j = i
while j > 1 && array[j].zero?
case j%2
when 1 # j is odd
j = 3*j + 1
when 0 # j is even
j = j/2
end
numstep += 1
end
stop = array[j] #if j has been solved, array[j] is the number of steps to j = 1. If j = 1, array[j] = 0
j = i
counter = 0
while j > 1 && array[j].zero?
if j < n
array[j] = numstep + stop - counter #numstep + stop should equal the solution to the ith number, to get the jth number we
end
case j%2
when 1 #j is odd
j = 3*j+1
when 0 #j is even
j = j/2
end
counter += 1
end
end
i = i-1
end
puts("Longest Collatz below #{n} @#{array.sort_by(&:first).map(&:last).each_with_index.max[1]} is #{arr
Please note, that since I used the hash with initializer, array[i]
can’t become nil
, that’s why the check is done for zero values only.