newbie : Ruby programming for factorials - ruby

So I got this question as an assignment in Computer class and I literally have no idea why the solution was such. I am hoping someone can explain it thoroughly to me.
My problem is:
How does one know that n*(n-1)*(n-2)*...*2*1 is actually just the math expression n! Is this just a magical formula that I have to remember? (Yes, I don't know much math beyond arithmetic)
Is there a better way of programming factorials
Write a method that takes an integer n in; it should return
n*(n-1)*(n-2)*...*2*1. Assume n >= 0.
As a special case, factorial(0) == 1.
Difficulty: easy.
def factorial(n)
if n < 0
return nil
end
result = 1
while n > 0
result = result * n
n -= 1
end
return result
end
puts("factorial(0) == 1: #{factorial(0) == 1}")
puts("factorial(1) == 1: #{factorial(1) == 1}")
puts("factorial(2) == 2: #{factorial(2) == 2}")
puts("factorial(3) == 6: #{factorial(3) == 6}")
puts("factorial(4) == 24: #{factorial(4) == 24}")

Yes, that is the definition of a factorial. One knows it by having learned the definition.
There are many ways to code up a factorial. Yours happens to be the most basic one. As you learn more about Ruby, you will start to be able to write more idiomatic code. For example...
def factorial_functional(n)
n < 0 ? nil : (1..n).inject(1, &:*)
end
def factorial_recursive(n)
return if n < 0
return 1 if n == 0
n * factorial_recursive(n - 1)
end
It is arguable what is "better", since there are so many factors: readability, conciseness, speed, memory usage... And readability is directly related to the target audience: I'm sure your code is more readable to you than either of my examples, but to someone experienced it is much more of a hassle to go through your longer code.

Amadan already showed better ways of writing the factorials method, but I believe you were also asking for an explanation of the solution you brought in.
# The method `factorial` receives a number `n` and returns `n!`.
def factorial(n)
if n < 0 # If the number `n` is negative
return nil # `n!` can't be calculated, so return nothing.
end # Otherwise, go on...
result = 1 # `result` is 1. For now...
while n > 0 # While the number `n` is positive
result = result * n # `result` becomes `result` times `n`.
n -= 1 # Decrease the number `n` by one.
end
# Once the number `n` becomes zero, `result` is
# equal to the multiplication of all numbers from 1
# to what `n` was at the very beginning.
return result # Return `result`
end
I would also like to contribute the following "better" way of defining the factorial method that can be read, more or less, in plain English:
def factorial(number)
return unless number.is_a? Integer and number >= 0
total = 1
number.downto 1 do |this_number|
total = total * this_number
end
return total
end

Related

Code Optimization - Generating Prime Numbers

I am trying to write a code for the following problem:
Input
The input begins with the number t of test cases in a single line (t<=10). In each of the next t lines there are two numbers m and n (1 <= m <= n <= 1000000000, n-m<=100000) separated by a space.
Output
For every test case print all prime numbers p such that m <= p <= n, one number per line, test cases separated by an empty line.
Sample Input:
2
1 10
3 5
Sample Output:
2
3
5
7
3
5
My code:
def prime?(number)
return false if number == 1
(2..number-1).each do |n|
return false if number % n == 0
end
true
end
t = gets.strip.to_i
for i in 1..t
mi, ni = gets.strip.split(' ')
mi = mi.to_i
ni = ni.to_i
i = mi
while i <= ni
puts i if prime?(i)
i += 1
end
puts "\n"
end
The code is running fine, only problem I am having is that it is taking a lot of time when run against big input ranges as compared to other programming languages.
Am I doing something wrong here? Can this code be further optimized for faster runtime?
I have tried using a for loop, normal loop, creating an array and then printing it.
Any suggestions.
Ruby is slower than some other languages, depending on what language you compare it to; certainly slower than C/C++. But your problem is not the language (although it influences the run-time behavior), but your way of finding primes. There are many better algorithms for finding primes, such as the Sieve of Eratosthenes or the Sieve of Atkin. You might also read the “Generating Primes” page on Wikipedia and follow the links there.
By the way, for the Sieve of Eratosthenes, there is even a ready-to-use piece of code on Stackoverflow. I'm sure a little bit of googling will turn up implementations for other algorithms, too.
Since your problem is finding primes within a certain range, this is the Sieve of Eratosthenes code found at the above link modified to suit your particular problem:
def better_sieve_upto(first, last)
sieve = [nil, nil] + (2..last).to_a
sieve.each do |i|
next unless i
break if i*i > last
(i*i).step(last, i) {|j| sieve[j] = nil }
end
sieve.reject {|i| !i || i < first}
end
Note the change from "sieve.compact" to a complexer "sieve.reject" with a corresponding condition.
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.

Comparing two Integers by their divisibility

For instance:
8 > 10 = true, since 8 is divisible by 2 three times and 10 only once.
How can I compare two integers from any range of numbers? Are the modulo and divide operator capable of doing this task?
Use binary caculate to judge it
def devided_by_two(i)
return i.to_s(2).match(/0*$/).to_s.count('0')
end
To make integer divisibility by 2, just transcode it to binary and judge how many zero from end of banary number. The code I provide can be more simple I think.
Yes, they are capable. A number is even if, when you divide it by two, the remainder is zero.
Hence, you can use a loop to continuously divide by two until you get an odd number, keeping a count of how many times you did it.
The (pseudo-code) function for assigning a "divisibility by two, continuously" value to a number would be something like:
def howManyDivByTwo(x):
count = 0
while x % 2 == 0:
count = count + 1
x = x / 2 # make sure integer division
return count
That shouldn't be too hard to turn into Ruby (or any procedural-type language, really), such as:
def howManyDivByTwo(x)
count = 0
while x % 2 == 0
count = count + 1
x = x / 2
end
return count
end
print howManyDivByTwo(4), "\n"
print howManyDivByTwo(10), "\n"
print howManyDivByTwo(11), "\n"
print howManyDivByTwo(65536), "\n"
This outputs the correct:
2
1
0
16
Astute readers will have noticed there's an edge case in that function, you probably don't want to try passing zero to it. If it was production code, you'd need to catch that and act intelligently since you can divide zero by two until the cows come home, without ever reaching an odd number.
What value you return for zero depends on needs you haven't specified in detail. Theoretically (mathematically), you should return infinity but I'll leave that up to you.
Notice that you will likely mess up much of your code if you redefine such basic method. Knowing that, this is how it's done:
class Integer
def <=> other
me = self
return 0 if me.zero? and other.zero?
return -1 if other.zero?
return 1 if me.zero?
while me.even? and other.even?
me /= 2
other /= 2
end
return 0 if me.odd? and other.odd?
return -1 if me.odd?
return 1 if other.odd? # This condition is redundant, but is here for symmetry.
end
end

Prime factoring returns nil when fed primes

I made a method that generates prime factors. Whatever composite number I push to it, it gives the prime factors. However, if I push a prime number into it, it wouldn't return 1 and the number itself. Instead, it would return 1 and some prime number smaller than the number pushed into the method.
I decided to shove an if statement that would cut the process short if the number pushed into turns out to be prime. Here's the code:
def get_prime_factors(number)
prime_factors = []
i = 0
primes = primes_gen(number)
if primes.include?(number)
return "Already a prime!"
end
original_number = number
while primes[i] <= original_number / 2
if number % primes[i] == 0
prime_factors << primes[i]
number = number / primes[i]
else
i = i + 1
end
if number == 1
return prime_factors
end
end
end
I fed 101 to the method and the method returned nil. This method calls the primes_gen method, which returns an array containing all primes smaller than the input value. Here it is:
def primes_gen(limit)
primes = []
i = 0
while i <= limit
primes << i if isprime?(i)
i = i + 1
end
primes.delete(0)
primes.delete(1)
return primes
end
I know there ought to be a more finessed way to fix the. If anyone wants to recommend a direction for me to explore as far as that goes, I'd be very grateful.
EDIT: Changed line 4 of the primes_gen() method to include a <= operator instead of a < operator.
Try changing primes = primes_gen(number) to primes = primes_gen(number+1) in first function and see if it works. Or try changing the i < limit condition to i <= limit in the second function.
Also, why are you deleting the 0th and 1st element in primes_gen method? Is it because of values you get for 0, 1? In which case, you can initialize with i=2.

Why is my Ruby code for Project Euler #10 so slow?

I am relatively new to Ruby but it seems simple enough as far as a language goes. I am working through the Euler Project with Ruby and I'm having a huge issue with speed on the following:
The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
Find the sum of all the primes below two million.
My code:
beginning_time = Time.now
(1..10000).each { |i| i }
def isPrime(num)
factors = 0
primecount = 1
while primecount <= num
if (num%primecount == 0)
factors += 1
end
if (factors > 2)
return false
end
primecount += 1
end
return true
end
def make_sieve(num)
sieve = Array.new(num)
summation = 0
for i in 1..num
if(isPrime(i) == true)
summation += i
puts i
for x in i..num
if x%i == 0
# Go through entire array and make all multiples of i False
sieve[x] = false
else
sieve[i] = true
end
end
else
# If i is NOT prime, move to the next number. in the For Loop
next
end
end
puts summation
end
make_sieve(2000000)
end_time = Time.now
puts "Time elapsed #{(end_time - beginning_time)*1000} milliseconds"
I think I have the right idea with the sieve but I really have no clue what's going on that makes this program run so slow. I run it with 20,000 and it takes about 15 seconds, which seems slow even still, although the output comes out MUCH faster than when I put 2,000,000.
Am I going about this the wrong way logically or syntactically or both?
Your isPrime() test is very slow on primes; but you don't even need it. The key to sieve is, initially all the numbers are marked as prime; then for each prime we mark off all its multiples. So when we get to a certain entry in the sieve, we already know whether it is a prime or not - whether it is marked true for being prime, or it is marked false for being composite (a multiple of some smaller prime).
There is no need to test it being prime, at all.
And to find the multiples, we just count: for 5, it's each 5th entry after it; for 7 - each 7th. No need to test them with % operator, just set to false right away. No need to set any of them to true, because all numbers were set to true at the start.
You seem to be writing JavaScript code in Ruby, and are missing the subtleties that makes Ruby so elegant. You should take a look at something like Ruby Best Practices, which is quite a light read but deals with using Ruby idioms instead of imposing the concepts of another language.
As has been said, the whole point of an Eratosthenes sieve is that you just remove all compound numbers from a list, leaving just the primes. There is no need to check each element for primeness.
This is a Rubyish solution. It runs in about 1.5 seconds. It is a little complicated by the representing number N by array element N-1, so (i+i+1 .. num).step(i+1) is equivalent to (n * 2 .. num).step(n)
def make_sieve(num)
sieve = Array.new(num, true)
sieve.each_with_index do |is_prime, i|
next if i == 0 or not is_prime
(i+i+1 .. num).step(i+1) { |i| sieve[i] = false }
end
puts sieve.each_index.select { |i| sieve[i] }.map { |i| i+1 }.inject(:+)
end
make_sieve(2_000_000)
output
142913828923

Can I reduce the computational complexity of this?

Well, I have this bit of code that is slowing down the program hugely because it is linear complexity but called a lot of times making the program quadratic complexity. If possible I would like to reduce its computational complexity but otherwise I'll just optimize it where I can. So far I have reduced down to:
def table(n):
a = 1
while 2*a <= n:
if (-a*a)%n == 1: return a
a += 1
Anyone see anything I've missed? Thanks!
EDIT: I forgot to mention: n is always a prime number.
EDIT 2: Here is my new improved program (thank's for all the contributions!):
def table(n):
if n == 2: return 1
if n%4 != 1: return
a1 = n-1
for a in range(1, n//2+1):
if (a*a)%n == a1: return a
EDIT 3: And testing it out in its real context it is much faster! Well this question appears solved but there are many useful answers. I should also say that as well as those above optimizations, I have memoized the function using Python dictionaries...
Ignoring the algorithm for a moment (yes, I know, bad idea), the running time of this can be decreased hugely just by switching from while to for.
for a in range(1, n / 2 + 1)
(Hope this doesn't have an off-by-one error. I'm prone to make these.)
Another thing that I would try is to look if the step width can be incremented.
Take a look at http://modular.fas.harvard.edu/ent/ent_py .
The function sqrtmod does the job if you set a = -1 and p = n.
You missed a small point because the running time of your improved algorithm is still in the order of the square root of n. As long you have only small primes n (let's say less than 2^64), that's ok, and you should probably prefer your implementation to a more complex one.
If the prime n becomes bigger, you might have to switch to an algorithm using a little bit of number theory. To my knowledge, your problem can be solved only with a probabilistic algorithm in time log(n)^3. If I remember correctly, assuming the Riemann hypothesis holds (which most people do), one can show that the running time of the following algorithm (in ruby - sorry, I don't know python) is log(log(n))*log(n)^3:
class Integer
# calculate b to the power of e modulo self
def power(b, e)
raise 'power only defined for integer base' unless b.is_a? Integer
raise 'power only defined for integer exponent' unless e.is_a? Integer
raise 'power is implemented only for positive exponent' if e < 0
return 1 if e.zero?
x = power(b, e>>1)
x *= x
(e & 1).zero? ? x % self : (x*b) % self
end
# Fermat test (probabilistic prime number test)
def prime?(b = 2)
raise "base must be at least 2 in prime?" if b < 2
raise "base must be an integer in prime?" unless b.is_a? Integer
power(b, self >> 1) == 1
end
# find square root of -1 modulo prime
def sqrt_of_minus_one
return 1 if self == 2
return false if (self & 3) != 1
raise 'sqrt_of_minus_one works only for primes' unless prime?
# now just try all numbers (each succeeds with probability 1/2)
2.upto(self) do |b|
e = self >> 1
e >>= 1 while (e & 1).zero?
x = power(b, e)
next if [1, self-1].include? x
loop do
y = (x*x) % self
return x if y == self-1
raise 'sqrt_of_minus_one works only for primes' if y == 1
x = y
end
end
end
end
# find a prime
p = loop do
x = rand(1<<512)
next if (x & 3) != 1
break x if x.prime?
end
puts "%x" % p
puts "%x" % p.sqrt_of_minus_one
The slow part is now finding the prime (which takes approx. log(n)^4 integer operation); finding the square root of -1 takes for 512-bit primes still less than a second.
Consider pre-computing the results and storing them in a file. Nowadays many platforms have a huge disk capacity. Then, obtaining the result will be an O(1) operation.
(Building on Adam's answer.)
Look at the Wikipedia page on quadratic reciprocity:
x^2 ≡ −1 (mod p) is solvable if and only if p ≡ 1 (mod 4).
Then you can avoid the search of a root precisely for those odd prime n's that are not congruent with 1 modulo 4:
def table(n):
if n == 2: return 1
if n%4 != 1: return None # or raise exception
...
Based off OP's second edit:
def table(n):
if n == 2: return 1
if n%4 != 1: return
mod = 0
a1 = n - 1
for a in xrange(1, a1, 2):
mod += a
while mod >= n: mod -= n
if mod == a1: return a//2 + 1
It looks like you're trying to find the square root of -1 modulo n. Unfortunately, this is not an easy problem, depending on what values of n are input into your function. Depending on n, there might not even be a solution. See Wikipedia for more information on this problem.
Edit 2: Surprisingly, strength-reducing the squaring reduces the time a lot, at least on my Python2.5 installation. (I'm surprised because I thought interpreter overhead was taking most of the time, and this doesn't reduce the count of operations in the inner loop.) Reduces the time from 0.572s to 0.146s for table(1234577).
def table(n):
n1 = n - 1
square = 0
for delta in xrange(1, n, 2):
square += delta
if n <= square: square -= n
if square == n1: return delta // 2 + 1
strager posted the same idea but I think less tightly coded. Again, jug's answer is best.
Original answer: Another trivial coding tweak on top of Konrad Rudolph's:
def table(n):
n1 = n - 1
for a in xrange(1, n // 2 + 1):
if (a*a) % n == n1: return a
Speeds it up measurably on my laptop. (About 25% for table(1234577).)
Edit: I didn't notice the python3.0 tag; but the main change was hoisting part of the calculation out of the loop, not the use of xrange. (Academic since there's a better algorithm.)
Is it possible for you to cache the results?
When you calculate a large n you are given the results for the lower n's almost for free.
One thing that you are doing is repeating the calculation -a*a over and over again.
Create a table of the values once and then do look up in the main loop.
Also although this probably doesn't apply to you because your function name is table but if you call a function that takes time to calculate you should cache the result in a table and just do a table look up if you call it again with the same value. This save you the time of calculating all of the values when you first run but you don't waste time repeating the calculation more than once.
I went through and fixed the Harvard version to make it work with python 3.
http://modular.fas.harvard.edu/ent/ent_py
I made some slight changes to make the results exactly the same as the OP's function. There are two possible answers and I forced it to return the smaller answer.
import timeit
def table(n):
if n == 2: return 1
if n%4 != 1: return
a1=n-1
def inversemod(a, p):
x, y = xgcd(a, p)
return x%p
def xgcd(a, b):
x_sign = 1
if a < 0: a = -a; x_sign = -1
x = 1; y = 0; r = 0; s = 1
while b != 0:
(c, q) = (a%b, a//b)
(a, b, r, s, x, y) = (b, c, x-q*r, y-q*s, r, s)
return (x*x_sign, y)
def mul(x, y):
return ((x[0]*y[0]+a1*y[1]*x[1])%n,(x[0]*y[1]+x[1]*y[0])%n)
def pow(x, nn):
ans = (1,0)
xpow = x
while nn != 0:
if nn%2 != 0:
ans = mul(ans, xpow)
xpow = mul(xpow, xpow)
nn >>= 1
return ans
for z in range(2,n) :
u, v = pow((1,z), a1//2)
if v != 0:
vinv = inversemod(v, n)
if (vinv*vinv)%n == a1:
vinv %= n
if vinv <= n//2:
return vinv
else:
return n-vinv
tt=0
pri = [ 5,13,17,29,37,41,53,61,73,89,97,1234577,5915587277,3267000013,3628273133,2860486313,5463458053,3367900313 ]
for x in pri:
t=timeit.Timer('q=table('+str(x)+')','from __main__ import table')
tt +=t.timeit(number=100)
print("table(",x,")=",table(x))
print('total time=',tt/100)
This version takes about 3ms to run through the test cases above.
For comparison using the prime number 1234577
OP Edit2 745ms
The accepted answer 522ms
The above function 0.2ms

Resources