 # Nil can't be coerced into Fixnum (TypeError)

I am trying to execute the following code and it seems like the array is
going out of bounds. Let me know where am I going wrong.

class PrimeFactor
def initialize(number)
@number = number
end

def primeFactors
factors = Array.new
(2…Math.sqrt(@number).ceil).each do |num|
if ( @number % num == 0 )
factors.insert(factors.length,num)
end
end
(0…factors.length).each do |i|
prime = factors[i]
factors = factors.select { |x| x == prime || x % prime !=0 }
end

``````factors.compact.join(',')
``````

end
end

prime = PrimeFactor.new(13195)
puts “#{prime.primeFactors}”

C:\Temp\Study\Ruby>ruby --version
ruby 1.8.7 (2011-02-18 patchlevel 334) [i386-mingw32]

C:\Temp\Study\Ruby>ruby prime.rb
prime.rb:16:in `%': nil can't be coerced into Fixnum (TypeError) from prime.rb:16:in`primeFactors’
from prime.rb:16:in `select' from prime.rb:16:in`primeFactors’
from prime.rb:14:in `each' from prime.rb:14:in`primeFactors’
from prime.rb:24

On Wed, Mar 23, 2011 at 10:57 AM, Mayank K. [email protected]
wrote:

(2…Math.sqrt(@number).ceil).each do |num|
end
from prime.rb:16:in `primeFactors' from prime.rb:16:in`select’
from prime.rb:16:in `primeFactors' from prime.rb:14:in`each’
from prime.rb:14:in `primeFactors’
from prime.rb:24

The problem with your code is that you are modifying the factors array
inside a precalculated iteration. Try adding some print statements in
the last loop you’ll see what’s going on:

[… snip…]
p factors.length
(0…factors.length).each do |i|
p factors
p i
prime = factors[i]
factors = factors.select { |x| x == prime || x % prime !=0 }
end

As you’ll see, you are modifying the array, but the each loop is still
going from 0 to 7. Another approach could be to set to nil the
multiples of each factor, and then compact:

factors.each do |factor|
next if factor.nil?
factors.each_with_index do |candidate,i|
next if candidate == factor
factors[i] = nil if candidate % factor == 0
end
end

BTW, your logic about the Math.sqrt being the top possible factor is
wrong (that’s used to know if a number is prime). For example, for 15,
Math.sqrt(15) is less than 4, and 5 is a factor of 15 which your logic
will skip. All in all, this works:

class PrimeFactor
def initialize(number)
@number = number
end

``````    def primeFactors
factors = Array.new
([email protected]).each do |num|
if ( @number % num == 0 )
factors.insert(factors.length,num)
end
end
p factors
factors.each do |factor|
next if factor.nil?
factors.each_with_index do |candidate,i|
next if candidate == factor
next if candidate.nil?
factors[i] = nil if candidate % factor
``````

== 0
end
end
factors.compact.join(’,’)
end
end

#prime = PrimeFactor.new(13195)
prime = PrimeFactor.new(ARGV.shift.to_i)
puts “#{prime.primeFactors}”

Maybe it can be further optimized, but you can start from here. This
is the ouput for 13195:

\$ ruby prime_factors.rb 13195
[5, 7, 13, 29, 35, 65, 91, 145, 203, 377, 455, 1015, 1885, 2639, 13195]
5,7,13,29

Jesus.

hey all,
so while Jesus’s implementation works, unless you want to implement a
prime number generator yourself you’re probably better off using Rubys
built-in Prime class (doc here:
http://rdoc.info/stdlib/prime/1.9.2/frames )
to do this. not only does it give you cleaner code, it is SIGNIFICANTLY
faster.

# the spiffified code

require ‘prime’ # you’re gonna need this
require ‘mathn’ # you’re gonna want this

class PrimeFactor
def initialize(number)
@number = number
end

def primeFactors
@factors = Prime.prime_division(@number,
Prime::TrialDivisionGenerator.new).flatten.uniq.sort.join(’, ')
end

end

#prime = PrimeFactor.new(13195)
prime = PrimeFactor.new(ARGV.shift.to_i)
puts “#{prime.primeFactors}”

in fact, benchmarking the two thusly:

# the benchmark code:

require ‘prime’ # you’re gonna need this
require ‘mathn’ # you’re gonna want this

require ‘benchmark’

class PrimeFactor_Long
def initialize(number)
@number = number
end

def primeFactors
factors = Array.new
(2…@number).each do |num|
if ( @number % num == 0 )
factors.insert(factors.length,num)
end
end
# p factors
factors.each do |factor|
next if factor.nil?
factors.each_with_index do |candidate,i|
next if candidate == factor
next if candidate.nil?
factors[i] = nil if candidate % factor == 0
end
end
factors.compact.join(’,’)
end
end

class PrimeFactor_Shrt
def initialize(number)
@number = number
end

def primeFactors
factors = Prime.prime_division(@number,
Prime::TrialDivisionGenerator.new).flatten.uniq.sort.join(’, ')
end

end

lots = 13195

bunches_of = 1_000

Benchmark.bmbm do |x|
x.report(‘Long’) do
bunches_of.times do
long = PrimeFactor_Long.new lots
long.primeFactors
end
end
x.report(‘Shrt’) do
bunches_of.times do
shrt = PrimeFactor_Shrt.new lots
shrt.primeFactors
end
end
end

puts

long = PrimeFactor_Long.new lots
puts “long factors: #{long.primeFactors}”

shrt = PrimeFactor_Shrt.new lots
puts “shrt factors: #{long.primeFactors}”

gives this:
[email protected]:~/src/test> ruby bench_prime.rb
Rehearsal ----------------------------------------
Long 3.160000 0.070000 3.230000 ( 3.523138)
Shrt 0.050000 0.000000 0.050000 ( 0.070737)
------------------------------- total: 3.280000sec

``````       user     system      total        real
``````

Long 3.010000 0.030000 3.040000 ( 3.227173)
Shrt 0.060000 0.000000 0.060000 ( 0.070470)

long factors: 5,7,13,29
shrt factors: 5,7,13,29

no joke… it’s more than 50x faster so yeah, unless this is a
project
for a class or something, use the included Prime class!
hex

2011/3/23 Jess Gabriel y Galn [email protected]

Nice I dint know about the Prime class available in stdlib. Thanks a
lot… –Mayank

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs