Ruby not incrementing number - ruby

I wrote code to find how many operations a number required under the Collatz Conjecture. However, my operations variable doesn't seem to be incrementing.
My code is:
puts "Please input a number"
number = gets.chomp
number = number.to_i
operations = 0
modulo = number % 2
while number =! 1
if modulo == 0
number = number / 2
operations = operations + 1
elsif modulo =! 0 && number =! 1
number = number * 3
number = number += 1
operations = operations + 2
else
puts "Uh oh, something went wrong."
end
end
puts "It took #{operations} operations!"
I am running this code on https://www.repl.it.

First of all, it's elsif; not elseif (I edited that in your question). And unequal sign is !=; not =!. But that has a somewhat different meaning. (i.e.: number =! 1 means number = !1)
In the 12th line, what is number = number += 1? I think you meant number += 1 or number = number + 1.
Now, the code works. :)
Here's the final version.
puts "Please input a number"
number = gets.chomp
number = number.to_i
operations = 0
modulo = number % 2
while number != 1
if modulo == 0
number = number / 2
operations = operations + 1
elsif modulo != 0 && number != 1
number = number * 3
number = number + 1
operations = operations + 2
else
puts "Uh oh, something went wrong."
end
end
puts "It took #{operations} operations!"
Usage:
Please input a number
256
It took 8 operations!
An optimal solution using functions:
def collatz(n)
if n % 2 == 0
return n / 2
else
return 3*n + 1
end
end
def chainLength(num)
count = 1
while num > 1
count += 1
num = collatz(num)
end
return count
end
puts "Please input a number"
number = gets.chomp
number = number.to_i
operations = chainLength(number)
puts "It took #{operations} operations!"
If you need more performance, read about dynamic programming and memoization techniques.

Related

A github autograding problem i couldn't figure out

i was given a homework by my instructor which i was supposed to upload into autograding system and i did.
And even though the program flawlessly works in my ruby interpreter, it prints an error in autograding system:
This is my output of the program:
Range: 1453-2011
Sum: 129339
Binary: 1 1 1 1 1 1 0 0 1 0 0 1 1 1 0 1 1
This is what resulted in autograding system:
❌ Example1
::error::The output for test Example1 did not match%0AExpected:%0ARange: 1453-2011%0ASum: 129339%0ABinary: 1 1 1 1 1 1 0 0 1 0 0 1 1 1 0 1 1%0AActual:%0ARange: 1453-2011%0ASum: 129339%0ABinary: 1 1 1 1 1 1 0 0 1 0 0 1 1 1 0 1 1
I didn't understand the reason why this error occurred at all. The output of my program is absolutely the same as the demanded output. Can you please explain?
It's basically a program that asks an input for which should be used to create an array with a range and the sum of the prime numbers within that range. It also asks for the binary representation of the sum of the prime numbers in that range:
# frozen_string_literal: true
def set_number(index1, index2) # Create an array with a range by asking the minimum and maximum points of the range specified by the user.
Array(index1..index2)
end
def prime?(number) # Is the number prime?
if number < 2
return false
elsif (2..Integer.sqrt(number)).each do
|divisor| if number % divisor == 0
return false
end
end
return number
end
end
def decimal_to_binary(number) # Convert the number from decimal to binary.
number = number.to_i
if number == 0
return 0
end
binary = []
while number != 0
binary = binary << String(number % 2)
number = number / 2
end
binary
end
index1, index2 = gets.chomp.split.map(&:to_i)
array = set_number(index1, index2)
puts "Range: #{index1}-#{index2}"
primes = []
array.each do |x|
primes << x if prime?(x)
end
sum = 0
primes.each {|element| sum = sum + element}
puts "Sum: #{sum}"
binary = decimal_to_binary(sum)
puts "Binary: #{binary.reverse.join(" " " ")}"
I expected the autograding system to verify the result which is correct and pass to the another example but it didn't.

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

my code result in an infinite loop

puts "enter a number"
x = gets.chomp.to_i
y = 0
while x != 1
y += 1
if x % 2 == 0
x = x / 2
else
x = x*3 + 1
end
print "#{x} "
end
puts "\nThe number of sequence is #{y+1}"
Hi, if I key in negative number or 0, I will get an infinite loop. How do I avoid entering the loop if my number is 0 or negative.
You can use x > 1 i.e
puts "enter a number"
x = gets.chomp.to_i
# if you want to consider negative as positive then x = gets.chomp.to_i.abs
y = 0
while (x > 1)
y += 1
if x % 2 == 0
x = x / 2
else
x = x*3 + 1
end
print "#{x} "
end
puts "\nThe number of sequence is #{y+1}"
Hope it helps
To answer your question:
Your code works perfectly well and does exactly what it is told to do:
while x is not 1 OR x is smaller than 0 do this codeblock.
If you set x to a negative number, x will never be a positive number, so it runs forever (because x is always smaller 0).
So, the code is correct, but there is a flaw in the logic behind it :)

Ruby armstrong numbers in a range

puts "Enter range(starts at 1), ends at the number that you enter: "
range = gets.chomp.to_i
number = 1
while number <= range
temporary_number = number
sum_angstrom = 0
number += number
while(temporary_number != 0)
digit = temporary_number % 10
temporary_number /= 10
sum_angstrom = sum_angstrom + (digit ** 3)
end
if (sum_angstrom == number)
puts number
end
end
This time, I tried to make a program to show the armstrong numbers in a range that's taken from the user's input. The program just stops after I enter the number and press enter and i can't figure out why.
Keep in mind that i can't use for(each), that's why i'm using while so often.
First of all, change number += number to number += 1; otherwise you will only test the powers of 2.
Second, move the number += 1 line at the bottom of the while block it is in. Otherwise you will always test if sum_armstrong(n) == n+1.
This works:
puts "Enter range(starts at 1), ends at the number that you enter: "
range = gets.chomp.to_i
number = 1
while number <= range
temporary_number = number
sum_angstrom = 0
while(temporary_number != 0)
digit = temporary_number % 10
temporary_number /= 10
sum_angstrom = sum_angstrom + (digit ** 3)
end
if (sum_angstrom == number)
puts number
end
number += 1
end
Armstrong Number in Ruby one liner
n = 153
s = 0
n.to_s.split("").map{|e| s+=(e.to_i*e.to_i*e.to_i)}
puts (n==s ? "Armstrong number" : "Not Armstrong number")
You can iterate in a range to print the value based on your requirement.
Main logic lies in below line.
n.to_s.split("").map{|e| s+=(e.to_i*e.to_i*e.to_i)}
Improving my answer a little bit
n.digits.map{|e| s+=(e**3)}

How do I describe all integers in Ruby

I'm trying to write a basic program that spits out the English version of a number when the user inputs a numeral:
input = 44
output = fourty four
Is there a way to describe all integers?
Basically I want the execution to look something like:
number = gets.chomp
if number != (whatever the nomenclature is for integer)
puts 'Please enter a positive number'
or something to that effect.
You can do that with the numbers_and_words gem:
https://github.com/kslazarev/numbers_and_words
It supports languages other than english as well.
For example:
21.to_words
=> "twenty-one"
44.to_words
=> "forty-four"
I modified the Fixnum class and added a method in_words. What I did is I broke each number up into groups of three, so 100000 turns into [100, 000] and 123456789 turns into [123, 456, 789] or 1543 turns into [1, 453] then I went element by element and named every number in the element and added the appropriate word, like hundred and thousand. If you have any questions I am happy to explain!
class Fixnum
LOW = %w(zero one two three four five six seven
eight nine ten eleven twelve thirteen fourteen
fifteen sixteen seventeen eighteen nineteen)
TWO_DIGIT = %w(ten twenty thirty forty fifty sixty seventy eighty ninety)
BIG_NUMS = %w(hundred thousand million billion trillion)
def in_words
# Break up number into bytes with three bits each
# Then turn each byte into words
# Break into bytes
number = self.to_s.reverse
bytes = []
num_bytes = (number.length.to_f / 3.0).ceil()
num_bytes.times { |x| bytes << number[(x*3)..(x*3)+2].reverse }
#puts bytes.reverse.join(",")
# Turn bytes into words bit by bit
word = []
text = ""
bytes.each_with_index do |byte, i|
text = ""
# First bit
text = LOW[byte[0].to_i] if (byte.length == 3 && byte[0].to_i != 0) || byte.length == 1
# Add hundred if 3 bits
text += " hundred" if byte.length == 3 && byte[0].to_i != 0
# Second bit
if byte.length == 3 # Three bits
if byte[1].to_i > 1 # Second bit greater than teens
text += " " + TWO_DIGIT[byte[1].to_i + (-1)]
elsif byte[1].to_i != 0 # Second bit not zero
text += " " + LOW[byte[1..2].to_i]
end
elsif byte.length == 2 # Two bits
if byte[0].to_i > 1 # Greater than teens
text += " " + TWO_DIGIT[byte[0].to_i + (-1)]
text += " " + LOW[byte[1].to_i] if byte[1].to_i != 0
else # Less than twenty
text += LOW[byte[0..1].to_i]
end
end
# Third bit if three bytes and second bit > teens and third bit nonzero
text += " " + LOW[byte[2].to_i] if byte[1].to_i != 1 && byte[2].to_i > 0 && byte.length > 2
# Add trillion/billion/million/thousand
text += " " + BIG_NUMS[i] if i != 0 && byte.to_i != 0
word << text.strip if text.strip != ""
end
word.reverse.join(" ")
end
end
Because I modified the Fixnum object, you can call this from any Fixnum e.g. 44.in_words
EDIT: It looks like you might be trying to check input for integers. I would recommend making a function to handle that:
def check_input(i)
if !(i =~ /^[0-9]+$/)
puts "Sorry, that is an invalid input! Please try again"
i = check_input(gets.chomp)
end
i.to_i
end
I think the best way to handle that is with regex (pattern matching). Basically your function checks if the input isn't a number, then it asks for input again. If it is a number, then the function returns the number. /^[0-9]+$/ is the regex. ^ means start of the line and $ means end of the line. [0-9] matches any digit zero through nine (as the Tin Man commented, you can also use \d to represent any digit and it is equivalent), and + means match the previous thing (any digit) at least once.

Resources