How can i avoid getting argument errors? [closed] - ruby

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 months ago.
Improve this question
i'm super new to ruby and i've been struggling with a problem in my code for hours which i don't seem to understand at all. When i execute the program, the output of the program says
./denem2.rb:1:in `ideal_weight': wrong number of arguments (given 0, expected 2) (ArgumentError)
from ./denem2.rb:15:in `<main>'
It's an extremely basic program that calculates the ideal weight for given parameters such "height" and "gender"
def ideal_weight(height, gender) # Ideal weight calculation
if gender == "E"
ideal_weight = (height - 100) - (height - 150) / 4
elsif gender == "K"
ideal_weight = (height - 100) - (height - 150) / 2
end
end
puts "Please enter your height, weight and gender..."
height, weight, gender = gets.chomp.split
height = height.to_i
weight = weight.to_i
ideal_weight(height, gender)
if ideal_weight < weight
puts "obese"
elsif ideal_weight == weight
puts "ideal"
elsif ideal_weight > weight
puts "light"
end
What i expected was that when i input the height and gender parameters, i should get a statement that says
things like "you're obese" or "you're in ideal state" or "you're light"

You define a method with the name ideal_weight, but then you use it in the if-elsif-else block as a variable. You need to store the result of the method call first.
In ruby it is not necessary to use brackets for a method call. Try for instance
puts 'Hello World'
puts('Hello World')
Now if ideal_weight < weight is interpreted as if ideal_weight() < weight, but the method takes two mandatory arguments. Moreover, you are having a method and a variable name of the same name. The interpreter does not know what to do/call in that case. You should find another name for the variable (or the method).
Working example
def ideal_weight(height, gender) # Ideal weight calculation
if gender == "E"
return (height - 100) - (height - 150) / 4
elsif gender == "K"
return (height - 100) - (height - 150) / 2
end
end
puts "Please enter your height, weight and gender..."
height, weight, gender = gets.chomp.split
height = height.to_i
weight = weight.to_i
ideal = ideal_weight(height, gender)
if ideal < weight
puts "obese"
elsif ideal == weight
puts "ideal"
elsif ideal > weight
puts "light"
end

Related

How to find lowest fixed balance in decimals using bisection in Ruby

How do I find the LOWEST FIXED monthly payment in 2 dp to pay off the balance with compounded interest for 12 months using bisection in ruby?
Disclaimer: I am applying upperBound and unpaidBalance formula correctly.
Test case:
find_fixed_payment(320000, 0.2) should return 29157.09
But my current method returns the middle value of 29591.87 which is way more than enough as the fixed payment (need to reduce to the lowest).
Where did my code went wrong as I am not sure how to do bisection (im using binary search)?
def find_fixed_payment(balance,annualInterestRate)
lowerBound = balance/12
upperBound = (balance * (1 + annualInterestRate/12)**12) / 12.0
unpaidBalance = balance
while true
middle = (lowerBound + upperBound )/2
#use middle as the monthly payment at first
(1..12).each do |i|
unpaidBalance = (unpaidBalance - middle) +
annualInterestRate / 12 * (unpaidBalance - middle)
end
temp = unpaidBalance.floor
if temp < 0
middle -= 0.01
upperBound = middle
# should go to for loop to reduce unpaid balance
# with new middle but not happening, why?
else
middle += 0.01
lowerBound = middle
end
if temp == 0
return middle
end
if upperBound == lower+1
return -1
end
return middle.round(2)
end
end
You made a lot of errors, I'm assuming you were transcribing this method from a reading somewhere, and simply failed to understand the process it was describing.
Basically you initialize all your starting variables, then you need the create the loop. Once in the loop, each time through you're calculating, you'll need to reset the balance back to 320,000 or it becomes a bit of a moving target and we'll never get the answer you're looking for.
I used the times method on the integer 12 to simulate the 12 month cycle, in your attempt you used a range and called the each method.
Now, I'm not sure why you were trying to adjust the value of middle like that, but it was a moot point because once it looped back to the beginning of your while true loop, it just went back to the original middle value. In my version I changed the upper or lower bound appropriately. Think of it like a number guessing of 1-10, you're smart enough to know you just pick the middle every time until you get it, and you would start with a lower bound of 1 and upper of 10, then guess 5. If I told you higher, you now know that 5 is your lower and 10 is still your upper.
Note: I hope this helps, and welcome other users feel free to critique and refactor my code, I only started ruby recently.
def find_fixed_payment(balance,annualInterestRate)
monthlyInterestRate = annualInterestRate / 12
lowerBound = balance/12
upperBound = (balance * (1 + monthlyInterestRate)**12) / 12.0
unpaidBalance = balance
accuracy = 0.01
while unpaidBalance.abs > accuracy
balance = unpaidBalance
middle = (lowerBound + upperBound) / 2
12.times do
newUnpaidBalance = unpaidBalance - middle
monthInterest = monthlyInterestRate * newUnpaidBalance
unpaidBalance = newUnpaidBalance + monthInterest
end
if unpaidBalance < 0
upperBound = middle
unpaidBalance = balance
elsif unpaidBalance > accuracy
lowerBound = middle
unpaidBalance = balance
end
end
middle.round(2)
end
find_fixed_payment(320000, 0.2)

How to check if input is an integer?- Ruby [duplicate]

This question already has answers here:
How to test if a string is basically an integer in quotes using Ruby
(19 answers)
Closed 6 years ago.
I have this code where I am entering input for sides of a triangle. Depending on the values, it will print it the triangle is equilateral, isoceles, or scalene. It's executing for number values, but how do I specify that the input should only be integers? For example, if I type in "w" , it should say invalid or error, but in this case, it executes. How do I solve this?
Basically, I am looking for a way to write that if a string were to be inputted, it should show up as an error (then I would write a print statement saying it is invalid). So could I put that into another if statement? (before the ones mentioned below)
Example Code:
puts "Enter the triangle length"
x = gets.chomp
puts "Enter the triangle width"
y = gets.chomp
puts "Enter the triangle height"
z = gets.chomp
if x == y and y == z
puts "This triangle is equilateral"
else if
x==y or y == z or x==z
puts "This triangle is isoceles"
else if
x!=y and y!=z and x!=z
puts "this triangle is scalene"
end
end
end
If you are dealing with integers, you can check this with ruby.
Note, this is not as robust as regex, but it covers most cases.
if (input != '0') && (input.to_i.to_s != input.strip)
# input is not a number
else
# input is a number
end
strip is there if you want to accept input with leading or trailing whitespace, otherwise you can leave it off.
While all the other answers are probably more or less robust, I would go with another one. Since you have a triangle sides lengths, they are to be greater than zero, right? Then one might use the side effect of String#to_i method: for everything that is not converting to integer it returns zero. Therefore:
x = gets.chomp.to_i
y = gets.chomp.to_i
z = gets.chomp.to_i
raise "Wrong input" unless x > 0 && y > 0 && z > 0
# ...
You can do something like this:
x = x.to_i
puts "Please enter an integer" if x == 0
Why?
Because:
"ABC".to_i # returns 0
You may be better off calling strip instead of chomp
gets.strip.to_i
An example:
## ruby user_age.rb
# input variables
name = ""
years = 0
MONTHS_PER_YEAR = 12 # a constant
# output variable
months = 0
# processing
print "What is your name? "
name = gets.strip
print "How many years old are you? "
years = gets.strip.to_i
puts "please enter an integer" if years == 0
months = years * MONTHS_PER_YEAR
puts "#{name}, at #{years} years old, "\
"you are #{months} months old."
There are several ways of doing it. If you allow for a leading sign,
x =~ /^[+-]?\d+$/
would be a possibility.
You will also have to think whether or not you allow surrounding or embedding spaces (for instance, a space between the sign and the first digit).
I assume that any string value that, when converted to a float, equals an integer is to be accepted and the integer value is to be returned. Moreover, I assume integers can be entered with the "xen" (or "xEn") notation, where x is an integer or float and n is an integer.
def integer(str)
x = Float(str) rescue nil
return nil if x==nil || x%1 > 0
x.to_i
end
integer("3") #=> 3
integer("-3") #=> -3
integer("3.0") #=> 3
integer("3.1") #=> nil
integer("9lives") #=> nil
integer("3e2") #=> 300
integer("-3.1e4") #=> -31000
integer("-30e-1") #=> -3
integer("3.0e-1") #=> nil
You could use Integer() to check if a string contains an integer:
Integer('1234')
#=> 1234
Integer('foo')
#=> ArgumentError: invalid value for Integer()
This could be combined with a retry:
begin
number = Integer(gets) rescue retry
end

How to convert miles into km and vice versa? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I cannot figure out how to create this conversion, something about math no matter how minute it is rattles my brain.
My class
class Distance
def convert(miles_to_km, km_to_miles)
miles_to_km = 1 * 1.60934
km_to_miles = 1 * 0.621371
end
end
or should it be something like
class Distance
def convert(value, unit)
some data i have yet to understand
end
end
my added input
puts "______________Adding: _____________"
d1 = Distance.new(1, "m")
d2 = Distance.new(1, "k")
puts d1 + d2
d1 = Distance.new(2, "M")
d2 = Distance.new(2, "m")
d3 = d1 + d2
puts d3
puts d3.value
puts d3.unit
d1 = Distance.new(3, "k")
d2 = Distance.new(3, "K")
puts d1 + d2
d1 = Distance.new(4, "k")
d2 = Distance.new(4, "m")
puts d1 + d2
puts "-" * 30 ############
Results should be
______________Adding _____________
1.621371 Miles
4 Miles
4
m
6 Kilometers
10.43736 Kilometers
Your methods need to be specific to your actions.
def convert(miles_to_km, km_to_miles)
miles_to_km = 1 * 1.60934
km_to_miles = 1 * 0.621371
end
Should be
def convert_miles_to_km(km)
return km * 1.60934
end
and vice versa
Parse String Arguments for Flexibility
There are lots of ways to solve this problem. A lot depends one what sort of input you expect from the caller, and what sort of result you want to pass back as your return values.
Sometimes it's useful to be less rigorous about how one expresses units of measurement while still being strict about the way the conversions are performed. Here is an example where a single method takes a string as input, and returns an appropriate floating-point value for predefined units such as kilometers or miles while remaining flexible about the way the distance units are expressed.
# Use constants for your conversion ratios.
MI_TO_KM = 1.60934
KM_TO_MI = 0.621371
# Make your method more flexible by accepting a string
# containing both a distance and a unit identifier.
def convert_distance str
dist, unit = str.scan(/([\d.]+)\s*(\S+)/).flatten
case unit
when /^k/i
dist.to_f * KM_TO_MI
when /^m/i
dist.to_f * MI_TO_KM
else
raise ArgumentError, "unknown unit: #{unit.inspect}"
end
end
This will provide you with the following sample outputs:
convert_distance '10 miles'
#=> 16.0934
convert_distance '10 kilometers'
#=> 6.21371
convert_distance '3mi'
#=> 4.82802
convert_distance '3km'
#=> 1.8641130000000001
convert_distance '1 cubit'
#=> ArgumentError: unknown unit: "cubit"
This type of method isn't necessarily the simplest way to get the job done, but it certainly prevents you from having to define different methods for "km", "kilometers", "klicks", and so forth. It's also easily expandable for other units of distance (e.g. "yards") simply by adding a new clause with the appropriate conversion ratio to the case statement.

Issue regarding variable alteration in Ruby [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have the following code...
#organisims.each do |organisim|
randomvalue = rand(10)
prediction = organisim.predict
if prediction == randomvalue
organisim.resources += 1
end
if prediction != randomvalue
organisim.resources -= 1
end
end
I am trying to alter the 'organisims' resources if the prediction it makes matches the randomly generated number. It seems to work fine, -1 if no match, +1 if there is a match.
The problem is that when I iterate this array (of organisims), processing their resources, I recieve duplicates in my output, such as
Cycle 100
Average resouces: 1500
Cycle 101
Average resouces: 1500
Then again,
Cycle 102
Average resouces: 1400
Cycle 103
Average resouces: 1400
Is this an issue with my code (I see no issues with it) or with the psudorandom number generator that Ruby uses?
Cheers as always
Martin
I think this may be an issue of the scope of your accumulator consider this example.
# example Organism class
class Organisim
attr_accessor :predict, :resources, :prediction
def initialize
#resources = 0
end
def predict
#prediction = rand(10)
#prediction
end
end
# initialize #organisims
#organisims = []
100.times do
#organisims << Organisim.new
end
puts "!!!! Starting Organisim Specific Run"
# iterate over array tracking organisim's resource
#organisims.each_with_index do |org, i|
# parrallel assignment
r, p = rand(10), org.predict
#ruby ternery operator
(p == r) ? org.resources += 1 : org.resources -= 1
puts "Run #{i} Prediction: #{org.prediction} Instance Resources: #{org.resources} Overall Resources: n/a"
end
puts "!!!! Cumulative Resource Run"
# resources scoped outside the iteration loop as accumulator
overall_resources = 0
# re-initialize #organisims
#organisims = []
100.times do
#organisims << Organisim.new
end
#organisims.each_with_index do |org, i|
# parrallel assignment
r, p = rand(10), org.predict
#ruby ternery operator
#track class level resource
(p == r) ? org.resources += 1 : org.resources -= 1
#iterate accumulator
(p == r) ? overall_resources += 1 : overall_resources -= 1
puts "Run #{i} Prediction: #{org.prediction} Instance Resources: #{org.resources} Overall Resources: #{overall_resources}"
end
The first iteration loop is like (I think) the one that you have in your question but you're changing the resource within the organisim object instance.
The second iteration your accumulator is outside the scope of your iteration so it grows and shrinks as the objects are acted upon. :-)

Optimizing this "Boundarize" method for Numerics in Ruby

I'm extending Numerics with a method I call "Boundarize" for lack of better name; I'm sure there are actually real names for this. But its basic purpose is to reset a given point to be within a boundary.
That is, "wrapping" a point around the boundary; if the area is betweeon 0 and 100, if the point goes to -1:
-1.boundarize(0,100) # => 99
(going one too far to the negative "wraps" the point around to one from the max).
102.boundarize(0,100) # => 2
It's a very simple function to implement; when the number is below the minimum, simply add (max-min) until it's in the boundary. If the number is above the maximum, simply subtract (max-min) until it's in the boundary.
One thing I also need to account for is that, there are cases where I don't want to include the minimum in the range, and cases where I don't want to include the maximum in the range. This is specified as an argument.
However, I fear that my current implementation is horribly, terribly, grossly inefficient. And because every time something moves on the screen, it has to re-run this, this is one of the bottlenecks of my application. Anyone have any ideas?
module Boundarizer
def boundarize min=0,max=1,allow_min=true,allow_max=false
raise "Improper boundaries #{min}/#{max}" if min >= max
raise "Cannot have two closed endpoints" if not (allow_min or allow_max)
new_num = self
if allow_min
while new_num < min
new_num += (max-min)
end
else
while new_num <= min
new_num += (max-min)
end
end
if allow_max
while new_num > max
new_num -= (max-min)
end
else
while new_num >= max
new_num -= (max-min)
end
end
return new_num
end
end
class Numeric
include Boundarizer
end
0.boundarize(10,50) # => 40
10.boundarize(0,10) # => 0 (the maximum is by default not allowed)
0.boundarize(0,20,false) # => 20 (the minimum is not allowed)
It looks to me like all you need is modulo (% operator) with a couple of extra checks to handle allow_min and allow_max:
irb(main):002:0> -1 % 100
=> 99
irb(main):003:0> -101 % 100
=> 99
irb(main):004:0> 102 % 100
=> 2
your operation is pretty much the modulo operation see here.
Ruby provides the operator % for that.

Resources