Factorial in Ruby - ruby

I'm trying to do in the Ruby program the summation of a factorial. and I can not solve. a clarification, when they run out points .... means that the logic is fine. if you get a F in one of the points, it means that the logic is wrong.
Write a program to calculate the sum of 1 + 1 / (2!) + 1 / (3!) + 1 / (4!) + .... + 1 / (n!) For a given n. Write the program in two ways: using While, For
def factorial(n)
#(n == 0) ? 1 : n * factorial(n - 1)
fact = 1
for i in 1..n
fact = fact * i
end
return fact
end
def sumatoriaWhile(n)
total = n
sumatoria = 0.0
while n > 1
total = total * (n - 1)
n = n - 1
sumatoria =sumatoria + total.to_f
end
return (1 + (1 / total.to_f)).round(2)
end
def sumatoriaFor(n)
fact = 1
sumatoria = 0.0
for i in 1..n
for j in 1..i
fact = fact * j
end
sumatoria = sumatoria + (1 / fact.to_f)
i = i + 1
end
return sumatoria.round(2)
end
#--- zona de test ----
def test_factorial
print validate(120, factorial(5))
print validate(5040, factorial(7))
print validate(362880, factorial(9))
end
def test_sumatoriaWhile
print validate(1.50, sumatoriaWhile(2))
print validate(1.83, sumatoriaWhile(3))
end
def test_sumatoriaFor
print validate(1.50, sumatoriaFor(2))
print validate(1.83, sumatoriaFor(3))
end
def validate (expected, value)
expected == value ? "." : "F"
end
def test
puts "Test program"
puts "---------------------------"
test_factorial
test_sumatoriaWhile
test_sumatoriaFor
puts " "
end
test

My friend, Thank you for your prompt response. First of all, I appreciate the help given. I am learning ruby programming and want to learn more as you and the other people. if indeed the answer is wrong. I have modified the answer. and also need to know what the function of While. and I hereby amended program again. and now I get an F on the part of WHILE.
def factorial(n)
fact = 1
for i in 1..n
fact = fact * i
end
return fact
end
def sumatoriaWhile(n)
total = n
sumatoria = 0.0
while n < 1
total = total * (n - 1)
sumatoria = sumatoria + (1.0 / total.to_f)
n = n - 1
end
return sumatoria.round(2)
end
def sumatoriaFor(n)
fact = 1
sumatoria = 0.0
for i in 1..n
fact = fact * i
sumatoria = sumatoria + (1.0 / fact.to_f)
end
return sumatoria.round(2)
end
#--- zona de test ----
def test_factorial
print validate(120, factorial(5))
print validate(5040, factorial(7))
print validate(362880, factorial(9))
end
def test_sumatoriaWhile
print validate(1.50, sumatoriaWhile(2))
print validate(1.67, sumatoriaWhile(3))
end
def test_sumatoriaFor
print validate(1.50, sumatoriaFor(2))
print validate(1.67, sumatoriaFor(3))
end
def validate (expected, value)
expected == value ? "." : "F"
end
def test
puts "Test de prueba del programa"
puts "---------------------------"
test_factorial
test_sumatoriaWhile
test_sumatoriaFor
puts " "
end
test

I have a hard time figuring out what you're doing in the summation function. Here's a straightforward function:
def sumatoriaFor(n)
return 0 if n <= 0
factorial = 1
sum = 0.0
for i in 1..n
factorial *= i
sum += 1.0 / factorial.to_f
end
return sum.round(2)
end
def sumatoriaWhile(n)
return 0 if n <= 0
i = 1
factorial = 1
sumatoria = 0.0
while i <= n
factorial *= i
sumatoria += (1.0 / factorial.to_f)
i = i + 1
end
return sumatoria.round(2)
end
The while look is straight forward too now. Also your validation is wrong:
1 + 1/2 + 1/6 ~= 1 + 0.5 + 0.17 = 1.67

Related

Ruby Number Guessing Game

I have tried to make a number guessing game using ruby but it seems to be looping all over again after the user gets the correct answer, here's my code and thanks in advance!
require './input_functions'
def check (rno,input)
x = 1
while (x == 1)
y = 0
if (rno > input)
puts("Try a bigger number")
input = gets.chomp.to_i
y = y + 1
x = 1
else
if (rno < input)
puts("Try a smaller number")
input = gets.chomp.to_i
y = y + 1
x = 1
else
if(rno == input)
puts("Bingo!")
x = 0
end
end
end
end
return
end
def main
rno = rand(100)
input = read_integer("Enter an integer between 0 and 100: ")
check(rno,input,y)
times = check(rno,input,y)
puts ("You have tried " + times.to_s + " times.")
end
main
The main problems are:
You call check method two times within main method, you need to remove the first one.
You need to move y = 0 out of while loop to be able to return it.
Tried to simplify your code a bit, and you could try to improve it even more.
def check(rno, input)
x = 1
y = 0
while x == 1
if rno == input
puts "Bingo!"
x = 0
else
if rno > input
puts "Try a bigger number"
else
puts "Try a smaller number"
end
input = gets.chomp.to_i
y = y + 1
end
end
return y
end
def main
rno = rand(100)
input = read_integer("Enter an integer between 0 and 100: ")
times = check(rno, input)
puts ("You have tried " + times.to_s + " times.")
end

Ruby - Why does this minor function change result in a big time difference?

This script is for Project Euler #14
I am refactoring it and all I did was grab 1 line of code n.even? ? n = n/2 : n = (3*n) + 1 and made it into it's own function. This change increase the execution time by 5 seconds.
Why would that happen?
Before:
def longest_collatz_sequence1(count)
check = []
while count >= 1
n = count
seq = [count]
while n > 1
n.even? ? n = n/2 : n = (3*n) + 1
seq << n
end
count -= 1
check << seq
value = sequence_check(check) if check.length == 2
end
puts "The number that produces the largest chain is: #{value[0][0]}"
end
def sequence_check(check)
check[0].length > check[1].length ? check.delete_at(1) : check.delete_at(0)
check
end
s = Time.new
longest_collatz_sequence1 1000000
puts "elapsed: #{Time.new-s}"
#~12.2 seconds
After:
def longest_collatz_sequence1(count)
check = []
while count >= 1
n = count
seq = [count]
while n > 1
n=collatz(n)
seq << n
end
count -= 1
check << seq
value = sequence_check(check) if check.length == 2
end
puts "The number that produces the largest chain is: #{value[0][0]}"
end
def collatz(n)
n.even? ? n = n/2 : n = (3*n) + 1
end
def sequence_check(check)
check[0].length > check[1].length ? check.delete_at(1) : check.delete_at(0)
check
end
s = Time.new
longest_collatz_sequence1 1000000
puts "elapsed: #{Time.new-s}"
#~17.7 seconds

How to I make floyd triangle shape using for loop?

I need output of Floyd triangle like:
1
0 1
1 0 1
0 1 0 1
I tried. I didn't get it exactly. Can anyone explain the logic?
This is the code I tried:
k = 0
for i in 1..5
for j in 1..5
if (i%2)==0;
k = (j%2==0) ? 1:0;
else;
k = (j%2==0) ? 0:1;
puts k,'';
end
end
puts
end
The main issue here is that in order to get the "triangle" shape of your output, you need your inner loop to increment from 1 to i instead of 1 to 5.
k = 0
for i in 1..5
for j in 1..i
if (i%2)==0
k = j + 1
else
k = j
end
print "#{k%2} "
end
puts
end
Here's a one line approach:
5.times {|line| puts (line + 1).times.with_object(""){|num, str| (num + line).even? ? (str << " 1 ") : (str << " 0 ") } }
to make it more clear:
lines = 5
lines.times do |line|
str = ""
line = line + 1 # 5.times runs from 0 to 4 and we need 1 to 5
line.times do |num|
# the condition is a bit different because I changes the code a bit
if (line + num).even?
str << " 0 "
else
str << " 1 "
end
end
puts str
end
Alright the following should work, but i hope it's readable. If you need more explanation or have specific questions let me know
i = 1
while i <= 4 do
if i%2 > 0
output = 1
else
output = 0
end
j = 1
while j <= i do
print( "#{output} " )
if output == 1
output = 0
else
output = 1
end
j+=1
end
print( "\n" )
i+=1
end
You can try following code for output you are expecting:
k = 0
for i in 1..4
for j in 1..i // inner loop code runs i times for each outer loop iteration
if (i%2)==0;
k = (j%2==0) ? 1:0;
else;
k = (j%2==0) ? 0:1;
end
print k,' ';
end
puts
end
Click Here to see output.
You can also get idea about for loops through this link.
The prefered ruby way:
layers = 4 # Change to as many layers as you want
layers.times do |i| # i starts from 0
(i + 1).times do |j| # j also starts from 0
print (i + j + 1) & 1, ' '
end
puts
end
The for way:
layers = 4
for i in 0...layers
for j in 0...(i + 1)
print (i + j + 1) & 1, ' '
end
puts
end

How do I calculate the factorial of a number in Ruby?

Alright, so I asked an earlier question on my syntax error. I got rid of the errors, but the program doesn't do what it was intended to do. My math is wrong and doesn't find the number of trailing zeros. Here is my code:
num = " "
a = 0
sumOfFact = 1
def factorial
num = gets.to_i
a = num
(1..num).each do |a|
if a != 1
sumOfFact *= a
a -= 1
else
break
end
end
end
for c in 1..sumOfFact
if sumOfFact / c == 10
zeros += 1
end
end
factorial()
puts sumOfFact
puts zeros
Well, first, you should do the gets outside your method. Your method should accept a param. Second, why do you need the condition?
You want the multiplication from 1 to n to get the factorial. You should get started with this:
def factorial(n)
total = 1
(1..n).each do |n|
total *= n
end
total
end
puts factorial(gets.to_i)
Next is factorial with inject in case you want to learn new syntax :-)
def factorial(n)
n == 0? 1 : (1..n).inject(1) { |total, i| total*= i; total }
end
puts factorial(gets.to_i)
As #pjs commented below, here's a beautiful way of doing factorial!
def factorial(n)
n == 0? 1 : (1..n).inject(:*)
end
And, a final enhancement:
def factorial(n)
(1..n).inject(1, :*)
end
Supposing that n is a non-negative integer number, you can define a method to calculate the factorial:
def factorial(n)
tot = 1
(1..n).each do |n|
tot *= x
end
tot
end
Examples of its usage:
puts factorial(0) # 1
puts factorial(1) # 1
puts factorial(2) # 2
puts factorial(3) # 6
puts factorial(4) # 24
puts factorial(5) # 120
If you wan't to read the user input, call it like this:
puts 'Type the non-negative integer:'
n = gets.to_i
puts factorial(n)
class Factorial
attr_reader :num
def initialize(num)
#num = num
end
def find_factorial
(1..num).inject(:*) || 1
end
end
number = Factorial.new(8).find_factorial
puts number
Or you could just simply write:
(1..num).inject(:*) || 1
Try this too. Hope this helps anyone having the same problem in some way.
Method for finding the factorial of any number:
def factorial(number)
for i in 1...number do
number *= i
end
number
end
puts factorial(5)

Better way to write this in Ruby?

I'm new to Ruby. After a ton of refactoring I came down to this. Is there a better way to write this?
51 def tri_num?(n)
52 i = 1
53 while i < n
54 return i if i * (i + 1) / 2 == n
55 i += 1
56 end
57 raise InvalidTree
58 end
What about solving it directly?
def tri_num? n
i = (0.5*(-1.0 + Math.sqrt(1.0 + 8.0*n))).to_i
if i*(i+1)/2 == n
return i
else
raise InvalidTree
end
end
Though I don't know if tri_num? is a good name. Usually a function ending with a ? should return true or false.
Yes.
def tri_num?(n)
1.upto(n-1) do |i|
return i if i * (i + 1) / 2 == n
end
raise InvalidTree
end
I thought the same as dantswain, basically invert the equation:
=> i * (i + 1) / 2 = n
=> i * (i + 1) = 2*n
=> i^2 + i = 2*n
=> i^2 + i -2*n = 0
And the solutions for the above are:
i = (-1 +- sqrt(1+8n))/2
Here I don't consider the - solution as it will give negative for any value of n bigger than 0, in the end the code is:
def tri_num?(n)
i = (-1 + Math.sqrt(1 + 8*n))/2.0
return i.to_i if i == i.to_i
raise InvalidTree
end
def tri_num?(n)
(1...n).each do |i|
return i if i * (i + 1) / 2 == n
end
rails InvalidTree # not defined..
end

Resources