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

Discussion in 'Ruby' started by Mayank K., Mar 23, 2011.

1. ### Mayank K.Guest

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
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

--
Posted via http://www.ruby-forum.com/.

Mayank K., Mar 23, 2011

2. ### Jesús Gabriel y GalánGuest

On Wed, Mar 23, 2011 at 10:57 AM, Mayank K. <> wrot=
e:
> 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
> =A0def initialize(number)
> =A0 =A0@number =3D number
> =A0end
>
> =A0def primeFactors
> =A0 =A0factors =3D Array.new
> =A0 =A0(2..Math.sqrt(@number).ceil).each do |num|
> =A0 =A0 =A0if ( @number % num =3D=3D 0 )
> =A0 =A0 =A0 =A0factors.insert(factors.length,num)
> =A0 =A0 =A0end
> =A0 =A0end
> =A0 =A0(0...factors.length).each do |i|
> =A0 =A0 =A0prime =3D factors
> =A0 =A0 =A0factors =3D factors.select { |x| x =3D=3D prime || x % prime !=

=3D0 }
> =A0 =A0end
>
> =A0 =A0factors.compact.join(',')
> =A0end
> end
>
> prime =3D 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)
> =A0 =A0 =A0 =A0from prime.rb:16:in `primeFactors'
> =A0 =A0 =A0 =A0from prime.rb:16:in `select'
> =A0 =A0 =A0 =A0from prime.rb:16:in `primeFactors'
> =A0 =A0 =A0 =A0from prime.rb:14:in `each'
> =A0 =A0 =A0 =A0from prime.rb:14:in `primeFactors'
> =A0 =A0 =A0 =A0from 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 =3D factors
factors =3D factors.select { |x| x =3D=3D prime || x % prime !=3D0 }
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 =3D=3D factor
factors =3D nil if candidate % factor =3D=3D 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 =3D number
end

def primeFactors
factors =3D Array.new
(2..@number).each do |num|
if ( @number % num =3D=3D 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 =3D=3D factor
next if candidate.nil?
factors =3D nil if candidate % factor =
=3D=3D 0
end
end
factors.compact.join(',')
end
end

#prime =3D PrimeFactor.new(13195)
prime =3D 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.

Jesús Gabriel y Galán, Mar 23, 2011

3. ### serialhexGuest

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 =3D number
end

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

end

#prime =3D PrimeFactor.new(13195)
prime =3D 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 =3D number
end

def primeFactors
factors =3D Array.new
(2..@number).each do |num|
if ( @number % num =3D=3D 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 =3D=3D factor
next if candidate.nil?
factors =3D nil if candidate % factor =3D=3D 0
end
end
factors.compact.join(',')
end
end

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

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

end

lots =3D 13195

bunches_of =3D 1_000

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

puts

long =3D PrimeFactor_Long.new lots
puts "long factors: #{long.primeFactors}"

shrt =3D PrimeFactor_Shrt.new lots
puts "shrt factors: #{long.primeFactors}"

gives this:
serialhex@livecd:~/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 Jes=FAs Gabriel y Gal=E1n <>

> On Wed, Mar 23, 2011 at 10:57 AM, Mayank K. <>
> wrote:
> > I am trying to execute the following code and it seems like the array i=

s
> > going out of bounds. Let me know where am I going wrong.
> >
> > class PrimeFactor
> > def initialize(number)
> > @number =3D number
> > end
> >
> > def primeFactors
> > factors =3D Array.new
> > (2..Math.sqrt(@number).ceil).each do |num|
> > if ( @number % num =3D=3D 0 )
> > factors.insert(factors.length,num)
> > end
> > end
> > (0...factors.length).each do |i|
> > prime =3D factors
> > factors =3D factors.select { |x| x =3D=3D prime || x % prime !=3D0=

}
> > end
> >
> > factors.compact.join(',')
> > end
> > end
> >
> > prime =3D 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

>
> 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 =3D factors
> factors =3D factors.select { |x| x =3D=3D prime || x % prime !=3D0 }
> 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 =3D=3D factor
> factors =3D nil if candidate % factor =3D=3D 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 =3D number
> end
>
> def primeFactors
> factors =3D Array.new
> (2..@number).each do |num|
> if ( @number % num =3D=3D 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 =3D=3D factor
> next if candidate.nil?
> factors =3D nil if candidate % factor =

=3D=3D 0
> end
> end
> factors.compact.join(',')
> end
> end
>
> #prime =3D PrimeFactor.new(13195)
> prime =3D 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.
>
>

serialhex, Mar 24, 2011
4. ### Mayank KohaleyGuest

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

--Mayank

On Thu, Mar 24, 2011 at 8:34 AM, serialhex <> wrote:

> 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/frame=

s)
> 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 =3D number
> end
>
> def primeFactors
> @factors =3D Prime.prime_division(@number,
> Prime::TrialDivisionGenerator.new).flatten.uniq.sort.join(', ')
> end
>
> end
>
> #prime =3D PrimeFactor.new(13195)
> prime =3D 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 =3D number
> end
>
> def primeFactors
> factors =3D Array.new
> (2..@number).each do |num|
> if ( @number % num =3D=3D 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 =3D=3D factor
> next if candidate.nil?
> factors =3D nil if candidate % factor =3D=3D 0
> end
> end
> factors.compact.join(',')
> end
> end
>
> class PrimeFactor_Shrt
> def initialize(number)
> @number =3D number
> end
>
> def primeFactors
> factors =3D Prime.prime_division(@number,
> Prime::TrialDivisionGenerator.new).flatten.uniq.sort.join(', ')
> end
>
> end
>
> lots =3D 13195
>
> bunches_of =3D 1_000
>
> Benchmark.bmbm do |x|
> x.report('Long') do
> bunches_of.times do
> long =3D PrimeFactor_Long.new lots
> long.primeFactors
> end
> end
> x.report('Shrt') do
> bunches_of.times do
> shrt =3D PrimeFactor_Shrt.new lots
> shrt.primeFactors
> end
> end
> end
>
> puts
>
> long =3D PrimeFactor_Long.new lots
> puts "long factors: #{long.primeFactors}"
>
> shrt =3D PrimeFactor_Shrt.new lots
> puts "shrt factors: #{long.primeFactors}"
>
>
> gives this:
> serialhex@livecd:~/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 projec=

t
> for a class or something, use the included Prime class!
> hex
>
>
>
>
> 2011/3/23 Jes=FAs Gabriel y Gal=E1n <>
>
> > On Wed, Mar 23, 2011 at 10:57 AM, Mayank K. <>
> > wrote:
> > > 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 =3D number
> > > end
> > >
> > > def primeFactors
> > > factors =3D Array.new
> > > (2..Math.sqrt(@number).ceil).each do |num|
> > > if ( @number % num =3D=3D 0 )
> > > factors.insert(factors.length,num)
> > > end
> > > end
> > > (0...factors.length).each do |i|
> > > prime =3D factors
> > > factors =3D factors.select { |x| x =3D=3D prime || x % prime !=

=3D0 }
> > > end
> > >
> > > factors.compact.join(',')
> > > end
> > > end
> > >
> > > prime =3D 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

> >
> > 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 =3D factors
> > factors =3D factors.select { |x| x =3D=3D prime || x % prime !=3D0 }
> > 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 =3D=3D factor
> > factors =3D nil if candidate % factor =3D=3D 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 =3D number
> > end
> >
> > def primeFactors
> > factors =3D Array.new
> > (2..@number).each do |num|
> > if ( @number % num =3D=3D 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 =3D=3D factor
> > next if candidate.nil?
> > factors =3D nil if candidate % factor=

=3D=3D
> 0
> > end
> > end
> > factors.compact.join(',')
> > end
> > end
> >
> > #prime =3D PrimeFactor.new(13195)
> > prime =3D 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.
> >
> >

>

--=20
Mayank Kohaley

Mayank Kohaley, Mar 24, 2011