User input to create factorial - ruby

Need some help on making the def fact(n) command to work off user input. My script works great when I input something like "Ruby factorial.rb 5". However, I need this to run with prompts. The script should run something like:
puts 'Please input a non-negative integer:'
n = gets.chomp.to_i
puts "The factorial of #{n} is #{factorial}
Here's what my code looks like now. Like I said however, it does work. It's when I add n = gets.chomp.to_i before the def fact(n) command that I automatically receive a value of 1. It doesn't matter what number the user puts in, it always returns 1.
#!/user/bin/ruby
def fact(n)
if n==0
1
else
n * fact(n-1)
end
end
puts fact(ARGV[0].to_i)
How do I make this work with the user input? I think I'm just having a syntax issue, but don't know how to make it work.

You actually seem to be asking for two different things. The first thing you want is an application that does something like this
$ ruby factorial.rb
> Please input a non-negative integer
(GET USER INPUT)
> The factorial of (USER INPUT) is (FACTORAIL OF USER INPUT)
And a command line tool that does something like this
$ fact 10
> 3628800
The first one could look something like this
def fact(n)
(1..n).inject(:*)
end
puts 'Please input a non-negative integer'
a = gets.to_i
puts "The factorial of #{a} is #{fact(a)}"
The second one could look something like this
#!/usr/bin/ruby
puts (1..ARGV[0].to_i).inject(:*)

Related

Simple program but so very stuck- Loops in Ruby

I have to write a program which asks the user to enter a number.
The program keeps on asking the user for a number until the user types 'Stop'
at which point the sum of the numbers that the user has entered should be printed.
I've tried many,many things and none of my ideas work.
This is what I have - but I can that it isn't correct. What am I doing wrong?
I've only used while loops and arrays
total_user_input = []
# As long as the user inputs a number, the program will keep putting Give me a number
# and then adding that number to the total_user_input array.
puts "Give me a number: "
while user_input = gets.chomp.to_i
#add the input to the array total_user_input
total_user_input.push(user_input.to_i)
puts "Give me a number: "
# If the user however types stop, then the loop is broken and we jump down to the
# sum bit - where all of the numbers in the total_user_input array are added together
# and printed. End of program!
if user_input == "stop"
break
end
sum = 0
total_user_input.each { |num|
sum += num
}
puts sum
end
The output isn't as it should be.
As others have identified the problems with your code let me suggest how you might reorganize it. Ruby provides many ways to execute loops but you many find it desirable to primarily relay on the method Kernel#loop and the keyword break. (As you will learn in time, loop is particularly convenient when used with enumerators.)
def sum_numbers
tot = 0
loop do
print 'Gimme a number: '
s = gets.chomp
break if s == 'Stop'
tot += s.to_i
end
tot
end
The keyword break can optionally take an argument (though why that is not mentioned in the doc I cannot say), in which case it (if a literal) or its value (if a variable or method) is returned by loop. Here one would generally see
break tot if s == 'Stop'
without the final line, tot. As the loop returns tot and that is the last calculation performed by the method, the method will return the final value of tot.
You could have instead written
return tot if user_input == 'Stop'
but I think most coders believe best practice dictates that one should not return from a method from within a loop (or from within nested loops) unless there is a good reason for doing so.
Some small points:
I used print rather than puts to that the user's entry will be shown on the same line as the prompt.
I used s (for "string") rather than user_input because it reduces the chance of spelling mistakes (e.g., user_imput), speeds reading, and (possibly a foible of mine), looks neater. True, s is not descriptive, but one only has to remember its meaning for three consecutive lines of code. Others may disagree.
You could write, break if s.downcase == 'stop' if you want, say, 'stop' or 'STOP' to have the same effect as 'Stop'.
'23O3'.to_i #=> 23 (that's an an oh, not a zero), so in real life you'd want to confirm that either 'Stop' or the string representation of a number had been typed.
This is how I would do this preferring to use loop do end syntax with a break when it should. Also added a bit more text so user knows what's happening.
total_user_input = []
puts 'Give me a number or "stop" to end: '
loop do
user_input = gets.chomp
total_user_input << user_input.to_i
puts "Give me a number: "
break if user_input.downcase == "stop"
end
puts "Total entered: #{total_user_input.inject(&:+)}" unless total_user_input.empty?
puts 'goodbye!'
Note these few things:
get.chomp.to_i will convert every input to integer. ("stop" or any non integer string will be 0)
Arrangement of the flow is quite messy.
total_user_input = []
puts "Give me a number: "
while user_input = gets.chomp.strip
total_user_input.push(user_input.to_i)
sum = 0
total_user_input.each { |num|
sum += num
}
puts sum
if user_input == "stop"
break
end
end
Hope you understand this.

Building a ruby factorial calculator

I'm working on writing a factorial program in ruby and I'm trying to write it where it does as follows:
Asks the user to enter a value to perform factorial on
takes in that value entered
performs factorial on it
and 4. returns the factorial value using "puts"
My goal is to get this to work then expand on this by building it out to include other statistical functions.
So far this is the code I have:
puts "Welcome to the Calculator for Ruby"
puts "Please enter your value to value"
#N factorial value
def n
n = gets.chomp
end
def fact
n * fact(n-1)
end
puts fact(n)
Fyi, I might add I've seen the generic factorial code available on the web but what I'm trying to do is set it so that the user defines n rather than setting n statically but when I try to do it, my code as above is erroring with the below error message:
"fact" : wrong number of arguments (1 for 0) (ArgumentError)
My apologies for some of the wording and not including a specific question. My question would be 3 parts:
How would I properly write the factorial calculation to operate on the user provided value? (Which I see was answered).
Once the calculation is performed how can I store that value so it persists in case the user wants to recall it for other calculations.
Lastly, are there any good sources for guidance in writing statistical functions in ruby?
Thank you to all for the assistance
No need to declare n using def, simply assign it (e.g. as n = gets.chomp).
You must include a named argument to your fact function, like def fact(x).
The fact(x) function needs a base case since you are using recursion.
You must convert the user input string n to a number, like n.to_i.
puts "Welcome to the Calculator for Ruby"
puts "Please enter your value to value"
def fact(x)
(x <= 1) ? 1 : x * fact(x-1)
end
n = gets.chomp.to_i
puts "#{n}! => #{fact(n)}"
Simpler way. Just inject numbers from 1 till n.
puts 'Welcome to the Calculator for Ruby'
puts 'Please enter your value to value'
n = gets.chomp.to_i
puts (1..n).inject(:*)
Might no be the best of solutions but here you go
puts "Welcome to the Factorial Calculator for Ruby"
puts "Please enter your value to exaluate"
n = gets.chomp.to_i
def fact(num)
return num <= 1 ? 1 : num * fact(num - 1)
end
puts "The factorial of #{n} is #{fact(n)}

Type Error - No implicit conversion from nil to integer - Creating a array

I'm new to Ruby. I'm trying to learn the dos and don'ts by making little programs. This program is a little redundant, but I wanna better myself with the syntax of the language.
Anyways, so I'm trying to create a little program that will ask the user for an amount of people. This amount of people will then reference the size of the array, then the program will ask the user to enter the names for each element in the array (which ALL be "nil" values since the new array's elements will be empty). Finally, I would want to print back the array to the console to see the completed elements.
However, I'm getting an error saying "Line 10: TypeError occured. No implicit conversion from nil to integer". My code is not 100% done. I'm still trying to add more stuff to it, but I want to troubleshoot this error first before I go about doing that. Anyone out there willing to help me out ?
Here's the code
def Array_Maker
puts "How many people would you like to enter? : "
num = gets.chomp.to_i
nameArray = Array.new(num)
puts "\nEnter the names of the people you wish to add: "
nameArray.each do |x|
nameArray[x] = gets.chomp.to_s
end
nameArray.each do |x|
puts x
end
end
Array_Maker()
I'm probably doing this all wrong, but I'm trying...
The line nameArray.each do |x| iterates over the array and x is set to the value of the array at each index.
A better way might be to build the array using a map method. Something like this:
def array_maker
puts "How many people would you like to enter? : "
num = gets.chomp.to_i
puts "\nEnter the names of the people you wish to add: "
nameArray = num.times.map do
gets.chomp.to_s
end
nameArray.each do |x|
puts x
end
end
array_maker()
nameArray.each do |x| In this loop, x is given the values of the Array which is nil
Try this.
for i in 0..num do
nameArray[i] = gets.chomp.to_s
end

How to run a simple Ruby script

I would like to make a program that checks to see if the number you enter is an even number. Sort of like making a leap year program but for any number divisible by 2.
Something along the lines of:
num = gets.chomp
while num != 0
if (num%2) == 0
puts 'yess'
else
puts 'nooo'
end
end
I knows there's something easy that I need to change for it to run.
(btw I just started learning Ruby yesterday!)
There are two problems here.
First being something that others have put, you need to make sure you turn the input into an integer using ".to_i" on your num variable.
Secondly, this code puts you into an infinite loop since you are using a "while" loop.
Since the number is only input once, you get stuck in the "while" loop forever no matter what the input is. Basically, "num" never stops being not 0.
You'd be better off using an if..else statement. Something like:
num = gets.chomp.to_i
if num != 0
if (num%2) == 0
puts 'yess'
else
puts 'nooo'
end
else
puts "that's 0, dude"
end
Integers have two methods for this. They are even? and odd?.
You can use this in your if statement as so:
if num.even?
puts 'yess'
else
puts 'nooo'
end
However, an easier way to write this is with ternary expressions:
puts num.even? ? "yes" : "no"
However, make sure num is an Integer. Anything coming from gets will be a String. So, you should be doing num = gets.chomp.to_i. Anything that is not a number, like "h", will return 0.
"5".to_i #=> 5
"h".to_i #=> 0

Stack too deep error on ruby, sqrt program for learning

So I'm aware of the Math.sqrt(number) method in Ruby, but as part of learning the language I thought it'd be a good idea to make some simple functions. I could be going about finding the square root wrong from a fundamental level, but here's what I did:
def negative?(number)
number < 0
end
#start = 2
def sqrt(number)
if negative? number
puts "Can't do negative"
else
if #start**2 < number
#start += 0.01
sqrt(number)
else
puts "Square root of #{number} is #{#start}!"
end
end
end
def start_sqrt
print "Input text: "
number = Integer(gets.strip)
sqrt(number)
end
begin
start_sqrt
rescue ArgumentError
puts "Need a positive number!"
end
This works fine for smaller numbers, but when I get to entering larger numbers I need to change the value of #start if I want to get an answer, otherwise it says "stack too deep". Is there something wrong I'm doing in the code, or is Ruby doing everything fine and I just am asking it to find the square root of a number in a resource-intensive way? I guess this is maybe even less of a programming question and more of a math question, cause I know I could just do:
def sqrt(number)
if negative? number
puts "Can't do negative"
else
root = number**0.5
puts "Square root of #{number} is #{root}!"
end
end
It looks like Ruby is working as expected. You are asking it to find the square root of a number in a resource-intensive way (recursion).
In fact, you have created a stack overflow error. :)

Resources