chrabyrd
chrabyrd

Reputation: 323

Using modulo on a range of numbers in Ruby

I'm making a program in ruby to find all of the prime factors of a given number. I'm aware that ruby has a .Prime class, but I'd like to accomplish this without using it.

Everything is working well except for one catch: I can't find a way to run modulo on a range of numbers. I've tried to find an answer online, in the Ruby documentation, and on older posts here. So far I've found nothing that helped.

Here's the code:

def prime(n)
    r = Range.new(2, n-1)
    r.each { |x| puts x if n % x == 0 && x % (2..x-1) != 0}
end

print "Please enter a number: "
prime(gets.chomp.to_i)

EDIT: Sorry, I may have been vague. This bit of code:

x % (2..x-1) != 0

Kicks back this:

euler2.rb:3:in `%': Enumerator can't be coerced into Fixnum (TypeError)
        from euler2.rb:3:in `block in divisible'
        from euler2.rb:3:in `each'
        from euler2.rb:3:in `divisible'
        from euler2.rb:7:in `<main>'

I've googled that error, but with no luck. If I change the code to a non-range, it works.

Upvotes: 0

Views: 539

Answers (2)

shivam
shivam

Reputation: 16506

Your logic is incorrect. You try something much simpler like:

def prime(n)
  !(2..n-1).detect{|x| n%x == 0}
end

Here detect will return the first value of x that matches the condition n%x == 0. If none matches nil is returned. Therefore in case of a prime number (2..n-1).detect{|x| n%x == 0} will return nil and ! will make it true. For composite numbers their lowest divisor will be returned and ! will make it false.

What is wrong with your code?

you are doing x % (2..x-1). Here (2..x-1) is a Range. You cannot do modulo of a Fixnum with a Range. Hence you will get:

TypeError: Range can't be coerced into Fixnum

You can improve x % (2..x-1) using something like (2..x-1).each{|n| x%n} or any other Enumerator in place of each. However I still think your logic is overly complicated or a simple problem like this.

Upvotes: 3

jcm
jcm

Reputation: 1789

How about any??

def prime(n)
  range = Range.new(2, n-1)
  composite = range.any? { |i| n%i == 0 }

  !composite
end

Of course this is going to be slow for large numbers.

Upvotes: 0

Related Questions