Can't get factorial function to work - ruby

Factorial 1 and 2 works but 3 and 4 do not. I've worked the steps out on paper and do not see why they do not work. Any help is much appreciated.
def factorial(n)
x = 1
y = n
while x < n
n = n * (y-x)
x = x + 1
end
return n
end
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}")

The reason it's not working is that after each loop the value of n gets bigger and the condition x < n keeps executing until it hits a point where n becomes zero. If you pass 3 to the function on the third loop you will have:
while x(3) < n(6)
n(6) = n(6) * (y(3) - x(3))
end
therefore n becomes 0 causing the loop to exit on the next round and the return value is obviously 0. To fix it you just need to replace n with y in the while condition:
while x < y
As a side note just another interesting way you could solve the factorial problem using recursion is:
def factorial(n)
n <= 1 ? 1 : n * factorial(n - 1)
end

Try this:
def factorial(n)
if n < 0
return nil
end
x = 1
while n > 0
x = x * n
n -= 1
end
return x
end

Related

How can I count number of iterations/steps to find answers of a method - RUBY

How can I get the number of iterations/steps that this method takes to find an answer?
def binary_search(array, n)
min = 0
max = (array.length) - 1
while min <= max
middle = (min + max) / 2
if array[middle] == n
return middle
elsif array[middle] > n
max = middle - 1
elsif array[middle] < n
min = middle + 1
end
end
"#{n} not found in this array"
end
One option to use instead of a counter is the .with_index keyword. To use this you'll need to use loop instead of while, but it should work the same. Here's a basic example with output.
arr = [1,2,3,4,5,6,7,8]
loop.with_index do |_, index| # The underscore is to ignore the first variable as it's not used
if (arr[index] % 2).zero?
puts "even: #{arr[index]}"
else
puts "odd: #{arr[index]}"
end
break if index.eql?(arr.length - 1)
end
=>
odd: 1
even: 2
odd: 3
even: 4
odd: 5
even: 6
odd: 7
even: 8
Just count the number of iterations.
Set a variable to 0 outside the loop
Add 1 to it inside the loop
When you return the index, return the count with it (return [middle, count]).
I assume the code to count numbers of interations required by binary_search is to be used for testing or optimization. If so, the method binary_search should be modified in such a way that to produce production code it is only necessary to remove (or comment out) lines of code, as opposed to modifying statements. Here is one way that might be done.
def binary_search(array, n)
# remove from production code lines marked -> #******
_bin_srch_iters = 0 #******
begin #******
min = 0
max = (array.length) - 1
loop do
_bin_srch_iters += 1 #******
middle = (min + max) / 2
break middle if array[middle] == n
break nil if min == max
if array[middle] > n
max = middle - 1
else # array[middle] < n
min = middle + 1
end
end
ensure #******
puts "binary_search reqd #{_bin_srch_iters} interations" #******
end #******
end
x = binary_search([1,3,6,7,9,11], 3)
# binary_search reqd 3 interations
#=> 1
binary_search([1,3,6,7,9,11], 5)
# binary_search reqd 3 interations
#=> nil

Something wrong with my PollardP1_rho code but I don't know how to fix it

I tried to use MillerRabin + PollardP1_rho method to factorize an integer into primes in Python3 for reducing time complexity as much as I could.But it failed some tests,I knew where the problem was.But I am a tyro in algorithm, I didn't know how to fix it.So I will put all relative codes here.
import random
def gcd(a, b):
"""
a, b: integers
returns: a positive integer, the greatest common divisor of a & b.
"""
if a == 0:
return b
if a < 0:
return gcd(-a, b)
while b > 0:
c = a % b
a, b = b, c
return a
def mod_mul(a, b, n):
# Calculate a * b % n iterately.
result = 0
while b > 0:
if (b & 1) > 0:
result = (result + a) % n
a = (a + a) % n
b = (b >> 1)
return result
def mod_exp(a, b, n):
# Calculate (a ** b) % n iterately.
result = 1
while b > 0:
if (b & 1) > 0:
result = mod_mul(result, a, n)
a = mod_mul(a, a, n)
b = (b >> 1)
return result
def MillerRabinPrimeCheck(n):
if n in {2, 3, 5, 7, 11}:
return True
elif (n == 1 or n % 2 == 0 or n % 3 == 0 or n % 5 == 0 or n % 7 == 0 or n % 11 == 0):
return False
k = 0
u = n - 1
while not (u & 1) > 0:
k += 1
u = (u >> 1)
random.seed(0)
s = 5 #If the result isn't right, then add the var s.
for i in range(s):
x = random.randint(2, n - 1)
if x % n == 0:
continue
x = mod_exp(x, u, n)
pre = x
for j in range(k):
x = mod_mul(x, x, n)
if (x == 1 and pre != 1 and pre != n - 1):
return False
pre = x
if x != 1:
return False
return True
def PollardP1_rho(n, c):
'''
Consider c as a constant integer.
'''
i = 1
k = 2
x = random.randrange(1, n - 1) + 1
y = x
while 1:
i += 1
x = (mod_mul(x, x, n) + c) % n
d = gcd(y - x, n)
if 1 < d < n:
return d
elif x == y:
return n
elif i == k:
y = x
k = (k << 1)
result = []
def PrimeFactorsListGenerator(n):
if n <= 1:
pass
elif MillerRabinPrimeCheck(n) == True:
result.append(n)
else:
a = n
while a == n:
a = PollardP1_rho(n, random.randrange(1,n - 1) + 1)
PrimeFactorsListGenerator(a)
PrimeFactorsListGenerator(n // a)
When I tried to test this:
PrimeFactorsListGenerator(4)
It didn't stop and looped this:
PollardP1_rho(4, random.randrange(1,4 - 1) + 1)
I have already tested the functions before PollardP1_rho and they work normally,so I know the function PollardP1_rho cannot deal the number 4 correctly,also the number 5.How can I fix that?
I have solved it myself.
There is 1 mistake in the code.
I should not use a var 'result' outside of the function as a global var,I should define in the function and use result.extend() to ensure the availability of the whole recursive process.So I rewrote PollardP1_rho(n, c) and PrimeFactorsListGenerator(n):
def Pollard_rho(x, c):
'''
Consider c as a constant integer.
'''
i, k = 1, 2
x0 = random.randint(0, x)
y = x0
while 1:
i += 1
x0 = (mod_mul(x0, x0, x) + c) % x
d = gcd(y - x0, x)
if d != 1 and d != x:
return d
if y == x0:
return x
if i == k:
y = x0
k += k
def PrimeFactorsListGenerator(n):
result = []
if n <= 1:
return None
if MillerRabinPrimeCheck(n):
return [n]
p = n
while p >= n:
p = Pollard_rho(p, random.randint(1, n - 1))
result.extend(PrimeFactorsListGenerator(p))
result.extend(PrimeFactorsListGenerator(n // p))
return result
#PrimeFactorsListGenerator(400)
#PrimeFactorsListGenerator(40000)
There is an additional tip: You don't need to write a function mod_mul(a, b, n) at all, using Python built-in pow(a, b, n) will do the trick and it is fully optimized.

Recursion for raising a number to a power

I have this code:
def power(x, n)
if n == 1
return x
else
x = x * power(x, n-1)
end
end
power(4, 4)
power(2, 3)
power(10, 3)
power(25, 2)
power(6, 5)
It takes the first number and raises it to the 2nd numberth power. So it works for all of them, but I want to write the code in a way that it prints the results for all 5 of the power functions. How do I do this? I tried to modify with puts instead of return but I cannot get it to work.
You have a variable x which points to the result of the method call. You can print this and then return it from the function:
def power(x, n)
if n == 1
return x
else
x = x * power(x, n-1)
puts x
x
end
end

Syntax error in simple program

I'm new to programming and I'm trying to program something but there's some kind of syntax error which I can't work out. Any help would be much appreciated. Here's my code:
begin
puts"Enter a number to count, or to exit type 0."
y = gets.chomp.to_i
if y == 0
exit
end
puts"Now put the number you're starting with"
x = gets.chomp.to_i
if y + x == 12 or y + x < 12
print x + y
end
if y + x > 12
n = y + x - 12
end
begin
if n < 12 or n == 12
print n
end
if n > 12
n = n - 12
end
end until if n < 12 or n == 12
end until y == 0
end
Your use of until if if wrong. They are each control sequences. You shouldn't need both.
Your n is not visible later in the code. Declare n=0 for example before if y + x > 12 to make it visible and accessible in the relevant code blocks.
Then, until if is wrong, this should simply be until
Lastly, delete the last end keyword.

algorithm to simulate multiplication by addition

How to design an algorithm to simulate multiplication by addition. input two integers. they may be zero, positive or negative..
def multiply(a, b):
if (a == 1):
return b
elif (a == 0):
return 0
elif (a < 0):
return -multiply(-a, b)
else:
return b + multiply(a - 1, b)
some pseudocode:
function multiply(x, y)
if abs(x) = x and abs(y) = y or abs(x) <> x and abs(y) <> y then sign = 'plus'
if abs(x) = x and abs(y) <> y or abs(x) <> x and abs(y) = y then sign = 'minus'
res = 0
for i = 0 to abs(y)
res = res + abs(x)
end
if sign = 'plus' return res
else return -1 * res
end function
val:= 0
bothNegative:=false
if(input1 < 0) && if(input2 < 0)
bothNegative=true
if(bothNegative)
smaller_number:=absolute_value_of(smaller_number)
for [i:=absolute_value_of(bigger_number);i!=0;i--]
do val+=smaller_number
return val;
mul(a,b)
{
sign1=sign2=1;
if(a==0 || b==0)
return 0;
if(a<0){
sign1=-1;
a=-a;
}
if(b<0){
sign2=-1;
b=-b;
}
s=a;
for(i=1;i<b;i++)
s+=a;
if(sign1==sign2)
return s;
else
return -s;
}
How about this for integers:
int multiply(int a, int b)
{
int product = 0;
int i;
if ( b > 0 )
{
for(i = 0; i < b ; i++)
{
product += a;
}
}
else
{
for(i = 0; i > b ; i--)
{
product -= a;
}
}
return product;
}
I got here because I was looking for multiplication algorithm without using * operation. All I see here is just adding or subtracting number n-times. It's O(n) and it's ok, but...
If you have bitwise shift operations you can get O(log n) algorithm for multiplication.
Here is my pseudocode:
function mul(n, x)
if n < 0 then # 'n' cannot be negative
n := -n
x := -x
endif
y := 0
while n != 0 do
if n % 2 == 0 then
x := x << 1 # x := x + x
n := n >> 1 # n := n / 2
else
y := y + x
x := x << 1 # x := x + x
n := n - 1 # n := (n-1)/2
n := n >> 1
endif
endwhile
return y # y = n * x
end
Remember that function above for mul(1000000, 2) is O(log 1000000) and for mul(2, 1000000) is only O(log 2).
Of course, you will get the same results, but keep in mind that the order of the parameters in function call does matter.
Edit: sidenote for using n % 2
Implementation of n % 2 using bitwise shift
It's pretty straightforward. First divide n by 2, then multiply n by 2 and check if n has changed. Pseudocode:
function is_even(n)
n_original := n
n := n >> 1 # n := n / 2
n := n << 1 # n := n * 2
if n = n_original then
return true # n is even
else
return false # n is not even
endif
end
Implementation of n % 2 using bitwise and
function is_even(n)
if n and 1 = 0 then
return true
else
return false
endif
end

Resources