Why doesnt my ruby coding for finding prime numbers work?
You have a few problems. One was identified earlier: the location of the statement i = 2
. Here is your code with that fixed.
def is_prime?(*nums)
nums.each do |num|
i = 2
while i < num
if num % i == 0
puts "#{num} is not a prime"
else
puts "#{num} is a prime"
end
i += 1
end
end
end
When num % i == 0
you've determined the number is not prime, and print a message to that effect, but then you continue checking to see if it is divisible all larger numbers less than num
. Each time num % i == 0
you print out that it's not prime. The point is that you don't need to keep checking once you determine a number is not prime.
Another problem is whenever num % i != 0
you print that the number is prime. That's premature, however. You can't draw that conclusion until you determine that num % i != 0
for all integers less than num
.
Let's see how to fix these problems. I think the easiest ways is to write a separate method that determines if a single number is prime. I've called that method is_prime?
and renamed the main method is_each_prime?
.
def is_each_prime?(*nums)
nums.each { |num|
puts "#{num} is #{ is_prime?(num) ? '' : "not " }a prime" }
end
def is_prime?(num)
(2...Math.sqrt(num)).all? { |i| num % i != 0 }
end
puts is_each_prime?(21, 23, 17)
#=> 21 is not a prime
# 23 is a prime
# 17 is a prime
One advantage of creating a separate method is_prime?
is that you can test it separately, to make sure it is working properly.
Ruby Prime number program
Let's calculate the square root of 7 (a prime number) and 8 (a composite number):
Math.sqrt(7) #=> 2.6457513110645907
Math.sqrt(8) #=> 2.8284271247461903
This doesn't really help, does it? Apparently, you can't determine if a number is a prime number by calculating its square root.
Instead, you have to check the number's divisors. From Wikipedia:
A prime number (or a prime) is a natural number greater than 1 that has no positive divisors other than 1 and itself.
Let's determine the divisors of 7: (using the modulo operator %
)
7 % 1 #=> 0 <- 7 is divisible by 1
7 % 2 #=> 1
7 % 3 #=> 1
7 % 4 #=> 3
7 % 5 #=> 2
7 % 6 #=> 1
7 % 7 #=> 0 <- 7 is divisible by 7
This satisfies the above definition - 7 is a prime number.
Now, let's determine the divisors of 8:
8 % 1 #=> 0 <- 8 is divisible by 1
8 % 2 #=> 0 <- 8 is divisible by 2
8 % 3 #=> 2
8 % 4 #=> 0 <- 8 is divisible by 4
8 % 5 #=> 3
8 % 6 #=> 2
8 % 7 #=> 1
8 % 8 #=> 0 <- 8 is divisible by 8
8 has two additional divisors 2 and 4. Therefore, 8 is not a prime number.
In Ruby, you could use select
to find the divisors:
(1..7).select { |d| 7 % d == 0 } #=> [1, 7]
(1..8).select { |d| 8 % d == 0 } #=> [1, 2, 4, 8]
Finally, here's a variant of your Ruby code that checks if a given number num
has exactly two divisors, 1
and num
itself:
prime_array = []
(1...100).each do |num|
if (1..num).select { |d| num % d == 0 } == [1, num]
prime_array.push(num)
end
end
prime_array
#=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
The above code can be optimized. I leave that to you.
Ruby - determine if a number is a prime
It's because =
is of higher precedence than or
. See Ruby's operator precedence table below (highest to lowest precedence):
[ ] [ ]=
**
! ~ + -
* / %
+ -
>> <<
&
^ |
<= < > >=
<=> == === != =~ !~
&&
||
.. ...
? :
= %= { /= -= += |= &= >>= <<= *= &&= ||= **=
defined?
not
or and
if unless while until
begin/end
The problematic line is being parsed as...
(foundDivider = ((n % d) == 0)) or foundDivider
...which is certainly not what you mean. There are two possible solutions:
Force the precedence to be what you really mean...
foundDivider = (((n % d) == 0) or foundDivider)
...or use the ||
operator instead, which has higher precedence than =
:
foundDivider = ((n % d) == 0) || foundDivider
Code Optimization - Generating Prime Numbers
Return true if the number is 2, false if the number is evenly divisible by 2.
Start iterating at 3, instead of 2. Use a step of two.
Iterate up to the square root of the number, instead of the number minus one.
def prime?(number)
return true if number == 2
return false if number <= 1 or number % 2 == 0
(3..Math.sqrt(number)).step(2) do |n|
return false if number % n == 0
end
true
end
This will be much faster, but still not very fast, as @Technation explains.
Here's how to do it using the Sieve of Eratosthenes built into Ruby. You'll need to precompute all the primes up to the maximum maximum, which will be very quick, and then select the primes that fall within each range.
require 'prime'
ranges = Array.new(gets.strip.to_i) do
min, max = gets.strip.split.map(&:to_i)
Range.new(min, max)
end
primes = Prime.each(ranges.map(&:max).max, Prime::EratosthenesGenerator.new)
ranges.each do |range|
primes.each do |prime|
next if prime < range.min
break if prime > range.max
puts prime
end
primes.rewind
puts "\n"
end
Here's how the various solutions perform with the range 50000 200000:
- Your original prime? function: 1m49.639s
- My modified prime? function: 0m0.687s
- Prime::EratosthenesGenerator: 0m0.221s
The more ranges being processed, the faster the Prime::EratosthenesGenerator method should be.
Related Topics
Rails 3.1 Load CSS in Particular Order
How to Use Reference Images in SASS When Using Rails 3.1
Unpermitted Parameters for Dynamic Forms in Rails 4
Simplest Way to Send Raw Byte-Arrays Using Ruby's Tcpsocket-Class
How to Create Email with CSS and Images from Rails
Best Way to Use Twitter Bootstrap Icons as Links in Ruby on Rails 3
Convert Hash Keys to Lowercase -- Ruby Beginner
Does Ruby Have Syntax for Safe Navigation Operator of Nil Values, Like in Groovy
Obtaining a Facebook Auth Token for a Command-Line (Desktop) Application
Is Regexp.Last_Match Thread Safe
Mismatched Bundler Version - Bundler 2, Ruby 2.6
Which Equality Test Does Ruby's Hash Use When Comparing Keys
Errno::Eaccess: Permission Denied @ Dir_S_Mkdir
Declaring an Integer Range with Step != 1 in Ruby
Override "Show" Resource Route in Rails