s is a string, This seems very long-winded - how can i simplify this? :
if x === 2
z = s
elsif x === 3
z = s+s
elsif x === 4
z = s+s+s
elsif x === 5
z = s+s+s+s
elsif x === 6
z = s+s+s+s+s
Thanks
Something like this is the simplest and works (as seen on ideone.com):
puts 'Hello' * 3 # HelloHelloHello
s = 'Go'
x = 4
z = s * (x - 1)
puts z # GoGoGo
API links
ruby-doc.org - String: str * integer => new_str
Copy—Returns a new String containing integer copies of the receiver.
"Ho! " * 3 #=> "Ho! Ho! Ho! "
z=''
(x-1).times do
z+=s
end
Pseudo code (not ruby)
if 1 < int(x) < 7 then
z = (x-1)*s
For example for a rating system up to 5 stars you can use something like this:
def rating_to_star(rating)
'star' * rating.to_i + 'empty_star' * (5 - rating.to_i)
end
Related
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 :)
I'm trying to make a simple * pyramid using while loops but it stops at the first five *. I can't figure out why.
This is my code:
x = 5
y = 0
while x > 0
while y < x
print "*"
y +=1
end
x -= 1
end
You never reset y or print a new line
x = 5
y = 0
while x > 0
while y < x
print "*"
y +=1
end
print "\n"
y = 0
x -= 1
end
Output
*****
****
***
**
*
That is bad Ruby tho
This is a much more idiomatic solution
5.downto(1) do |x|
1.upto(x) do |y|
print "*"
end
print "\n"
end
Output
*****
****
***
**
*
I don't know what the final shape of "pyramid" you're looking for, but you can likely adapt the technique above to get the desired output
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.
For a school's assignment I am trying to calculate pi using the Gauss Legendre algorithm to test cpu efficiency.
Therefore, I have written a program in Ruby.
This program should iterate 500000000 times and display the the time used for it. But everytime it executes within a second.
My question:
Is there a better way to iterate so it really does repeat 500 million times and display pi and the time?
include Math
a = 1
b = 1/sqrt(2)
t = 0.25
p = 1
i = 0
imax = 500000000
start = Time.now
until i = imax
an = (a/2) + (b/2)
bn = sqrt(a) * sqrt(b)
tn = t - p * ((a-an) * (a-an))
pn = 2 * p
a = an
b = bn
t = tn
p = pn
i +=1
PI = ((a+b)*(a+b))/(4*t)
end
finish = Time.now
time = finish - start
puts PI
puts time
Start by not making i equal imax right away:
until i = imax
Should be
until i == imax
Even better, just do
500000000.times do
Instead of that line.
In addition to the issues raised by #Nick and #sawa your algorithm is flawed: the square root of the product of a and b is not equal to the product of the square roots of a and b.
In ruby:
include Math
a, b, t, p = 1, 1/sqrt(2), 0.25, 1
imax = 5
imax.times do |i|
an = (a+b) / 2
bn = sqrt(a * b)
tn = t - p * ((a-an) * (a-an))
pn = 2 * p
a, b, t, p = an, bn, tn, pn
pi = ((a+b)*(a+b))/(4*t)
printf "%d : %10.60f\n", i, pi
end
Running this gives me:
0 : 3.140579250522168575088244324433617293834686279296875000000000
1 : 3.141592646213542838751209274050779640674591064453125000000000
2 : 3.141592653589794004176383168669417500495910644531250000000000
3 : 3.141592653589794004176383168669417500495910644531250000000000
4 : 3.141592653589794004176383168669417500495910644531250000000000
So clearly you need more accuracy, hence BigDecimal. As this is your homework assignment I'll leave that up to you :-). (If unsure which variables to change, try all except i and imax. Also check out http://www.ruby-doc.org/stdlib-1.9.3/libdoc/bigdecimal/rdoc/BigDecimal.html)
Another thing you are doing wrong is assigning a constant PI within a loop. Although it is possible to reassign a constant, it is not correct to do so. Either use a variable or move the assignment to outside of the loop so that it would be assigned only once.
Even if I remove the assignment and print out the result for each iteration like this:
include Math
a = 1
b = 1/sqrt(2)
t = 0.25
p = 1
i = 0
imax = 500000000
until i == imax
an = (a/2) + (b/2)
bn = sqrt(a) * sqrt(b)
tn = t - p * ((a-an) * (a-an))
pn = 2 * p
a = an
b = bn
t = tn
p = pn
i +=1
puts ((a+b)*(a+b))/(4*t)
end
I get the wrong result. It goes like this:
-2.1244311544725596
-1.1383928808463357
-1.1265990444799223
-1.1265961703346379
-1.126596170334544
-1.126596170334544
... # very long repetition of the same number
-1.126596170334544
-1.126596170334544
NaN
NaN
... # NaN forever
Something must be wrong with your algorithm.
I have the following method for doing a check digit on a tracking number, but it just feels lengthy/sloppy. Can it be refactored and just generally cleaned up?
I'm running Ruby 1.8.7.
def is_fedex(number)
n = number.reverse[0..14]
check_digit = n.first.to_i
even_numbers = n[1..1].to_i + n[3..3].to_i + n[5..5].to_i + n[7..7].to_i + n[9..9].to_i + n[11..11].to_i + n[13..13].to_i
even_numbers = even_numbers * 3
odd_numbers = n[2..2].to_i + n[4..4].to_i + n[6..6].to_i + n[8..8].to_i + n[10..10].to_i + n[12..12].to_i + n[14..14].to_i
total = even_numbers + odd_numbers
multiple_of_ten = total + 10 - (total % 10)
remainder = multiple_of_ten - total
if remainder == check_digit
true
else
false
end
end
EDIT: Here are valid and invalid numbers.
Valid: 9612019950078574025848
Invalid: 9612019950078574025847
def is_fedex(number)
total = (7..20).inject(0) {|sum, i| sum + number[i..i].to_i * ( i.odd? ? 1 : 3 ) }
number[-1].to_i == (total / 10.0).ceil * 10 - total
end
I believe you should keep your code. While it's not idiomatic or clever, it's the one you will have the least trouble to understand a few months from now.
I'm not a ruby programmer, so if any of the syntax is off, I apologize but you should get the general idea. A few things I see: First, you don't need to slice the array, a single index should be sufficient. Second, Instead of splitting even and odd, you could do something like this:
total = 0
for i in (1..14)
total += n[i].to_i * ( i % 2 == 1 ? 1 : 3 )
end
Third, remainder could be simplified to 10 - (total % 10).
I realize you're running 1.8.7, but here's my attempt using each_slice and inject in conjunction, a 1.9.2 feature:
def is_fedex(number)
total = number.reverse[1..14].split(//).map(&:to_i).each_slice(2).inject(0) do |t, (e,o)|
t += e*3 + o
end
10 - (total % 10) == number[-1].to_i
end
It passes both tests
Give this a try:
#assuming number comes in as a string
def is_fedex(number)
n = number.reverse[0..14].scan(/./)
check_digit = n[0].to_i
total = 0
n[1..14].each_with_index {|d,i| total += d.to_i * (i.even? ? 3 : 1) }
check_digit == 10 - (total % 10)
end
> is_fedex("12345678901231") => true
edit incorporating simplified remainder logic as Kevin suggested
Something like this?
def is_fedex(number)
even_arr, odd_arr = number.to_s[1..13].split(//).map(&:to_i).partition.with_index { |n, i| i.even? }
total = even_arr.inject(:+) * 3 + odd_arr.inject(:+)
number.to_s.reverse[0..0].to_i == (total + 10 - (total % 10)) - total
end
If you can give me a valid and invalid number I can test if it works and maybe tweak it further :)
This function should to:
def is_fedex(number)
# sanity check
return false unless number.length == 15
data = number[0..13].reverse
check_digit = number[14..14].to_i
total = (0..data.length-1).inject(0) do |total, i|
total += data[i..i].to_i * 3**((i+1)%2)
end
(10 - total % 10) == check_digit
end
The arithmetic expression 3**((i+1)%2) might look a bit complex, but is essentially the same as (i.odd? ? 1 : 3). Both variants are correct, which you use is up to you (and might affect speed...)
Also note, that if you use Ruby 1.9, you can use data[i] instead of data[i..i] which is required for for Ruby 1.8.