I am trying to convert a variable, which will always be a number, into binary, octal, and hex with Ruby.
The code I have at this point is:
def convert(number)
puts "#{number} in decimal is"
puts "#{number.to_s(2)} in binary"
puts "#{number.to_s(8)} in octal"
puts "#{number.to_s(16)} in hexadecimal"
end
and so far the output is:
2 in decimal is
10 in binary
2 in octal
2 in hexadecimal
The first two lines run fine, but after that it is ignoring the conversion command and just putting the variable in. Does anyone have any idea what it is I am missing?
You are missing the fact that 2 is... 2 in base 8, 16, or any base greater than 2. Try convert(42) for fun.
Related
My ruby command is,
"980,323,344.00".to_i
Why does it return 980 instead of 980323344?
You can achieve it by doing this :
"980,323,344.00".delete(',').to_i
The reason your method call to to_i does not return as expected is explained here, and to quote, the method :
Returns the result of interpreting leading characters in str as an integer base base (between 2 and 36). Extraneous characters past the end of a valid number are ignored.
Extraneous characters in your case would be the comma character that ends at 980, the reason why you see 980 being returned
In ruby calling to_i on a string will truncate from the beginning of a string where possible.
number_string = '980,323,344.00'
number_string.delete(',').to_i
#=> 980323344
"123abc".to_i
#=> 123
If you want to add underscores to make longer number more readable, those can be used where the conventional commas would be in written numbers.
"980_323_344.00".to_i
#=> 980323344
The documentation for to_i might be a bit misleading:
Returns the result of interpreting leading characters in str as an integer base base (between 2 and 36)
"interpreting" doesn't mean that it tries to parse various number formats (like Date.parse does for date formats). It means that it looks for what's a valid integer literal in Ruby (in the given base). For example:
1234. #=> 1234
'1234'.to_i #=> 1234
1_234. #=> 1234
'1_234'.to_i. #=> 1234
0d1234 #=> 1234
'0d1234'.to_i #=> 1234
0x04D2 #=> 1234
'0x04D2'.to_i(16) #=> 1234
Your input as a whole however is not a valid integer literal: (Ruby doesn't like the ,)
980,323,344.00
# SyntaxError (syntax error, unexpected ',', expecting end-of-input)
# 980,323,344.00
# ^
But it starts with a valid integer literal. And that's where the the seconds sentence comes into play:
Extraneous characters past the end of a valid number are ignored.
So the result is 980 – the leading characters which form a valid integer converted to an integer.
If your strings always have that format, you can just delete the offending commas and run the result through to_i which will ignore the trailing .00:
'980,323,344.00'.delete(',') #=> "980323344.00"
'980,323,344.00'.delete(',').to_i #=> 980323344
Otherwise you could use a regular expression to check its format before converting it:
input = '980,323,344.00'
number = case input
when /\A\d{1,3}(,\d{3})*\.00\z/
input.delete(',').to_i
when /other format/
# other conversion
end
And if you are dealing with monetary values, you should consider using the money gem and its monetize addition for parsing formatted values:
amount = Monetize.parse('980,323,344.00')
#=> #<Money fractional:98032334400 currency:USD>
amount.format
#=> "$980.323.344,00"
Note that format requires i18n so the above example might require some setup.
I can convert an object to an integer with to_i. How can I get it to not convert if the input is not a number?
In python I would do this:
h=input("Number: ")
try:
h=int(h)
except ValueError:
print("Please enter numbers!")
So I tried this in ruby:
print "Number: "
h=gets.chomp
try(h.to_i)
print(h)
end
but it prints the input even if I enter letters, so this means I am doing it wrong. What is the correct Ruby way of doing this?
Reading ruby docs for to_i
Returns the result of interpreting leading characters in str as an
integer base base (between 2 and 36). Extraneous characters past the
end of a valid number are ignored. If there is not a valid number at
the start of str, 0 is returned. This method never raises an exception
when base is valid.
What you want in your case (to map the Python behavior) is:
begin
Integer(gets)
rescue ArgumentError
puts "Please enter numbers!"
end
This question already has answers here:
Why is 032 different than 32 in Ruby? [duplicate]
(4 answers)
Closed 8 years ago.
So I wanted to get my fundamental ruby skills up (coming from a python background) because I wanted to get a good handle on rails.
I was doing a bunch of exercises I picked for myself, and this particular error came up (it's not quite an error, but I'm raising an eyebrow) - for what it's worth, I'm using ruby 2.0.0.
Class A
def B(binaryNum)
puts binaryNum
binarray = binaryNum.to_s.chars.to_a
indice = binarray.length
puts "\n#{indice}"
end
end
conv = A.new()
puts "#{conv.B(1111)}" # outputs 1111 as usual, with a length of 4
puts "#{conv.B(01111)}" # outputs 585, with a length of 3
It seems putting a zero in front of the integer representation of binary is causing all sorts of ruckus to occur. I initially thought it might be a silly error regarding maximum ints, but I reproduced the issue with much smaller numbers.
Ruby's numeric syntax is similar to C's, and the leading zero tells it to interpret the number as octal (base 8).
1111 base 8 = 585 base 10.
Numeric literals with leading zeros in Ruby are treated as octal numbers.
According to the ruby-doc.org documentation for numeric literals:
You can use a special prefix to write numbers in decimal, hexadecimal,
octal or binary formats. For decimal numbers use a prefix of 0d, for
hexadecimal numbers use a prefix of 0x, for octal numbers use a prefix
of 0 or 0o, for binary numbers use a prefix of 0b. The alphabetic
component of the number is not case-sensitive.
Examples:
0d170
0D170
0xaa
0xAa
0xAA
0Xaa
0XAa
0XaA
0252
0o252
0O252
0b10101010
0B10101010
So in your case, since 11118 = 58510, 01111.to_s will return "585".
Note that Fixnum#to_s takes an argument which lets you specifiy the base of the number system you are using. So for your program, you could do it like this:
class A
def B(binaryNum)
puts binaryNum
binarray = binaryNum.to_s(2).chars.to_a
indice = binarray.length
puts "\n#{indice}"
end
end
conv = A.new
puts "#{conv.B(0b1111)}" # Outputs 15, with a length of 4
puts "#{conv.B(01111)}" # Outputs 585, with a length of 10
puts "#{conv.B(1111)}" # Outputs 1111, with a length of 11
Even better, in Ruby 2.1+ Fixnum has an instance method called bit_length which seems to already do what you want:
0b1.bit_length
#=> 1
0b11.bit_length
#=> 2
0b111.bit_length
#=> 3
0x1FF.bit_length
#=> 9
Very simply put, when I try to insert an integer into a method, then convert it into a string, and print out the first character into the string, I get the number in the [0] slot + 48. Without fail, I get slot + 48. I'm extremely perplexed because I believe I should be getting the number in that slot. Example:
def print_number(num)
number = num.to_s
print number[0]
end
Without fail, I will receive x + 48.
print_number(2) #=> 50 (Believe I should get 2)
print_number(5) #=> 53 (Believe I should get 5)
print_number(123) #=> 49 (Believe I should get 4)
print_number(42) #=> 52 (Believe I should get 5)
print_number(22) #=> 50 (Believe I should get 5)
print_number(1) #=> 49 (Believe I should get 5)
Why?
When accessing Strings like you do, there is a difference between Ruby 1.8 and Ruby 1.9. In Ruby 1.9, you get the first character in whatever encoding the string has (which can consist of multiple bytes when e.g. using UTF-8).
Ruby 1.8 is not encoding aware, thus string[0] always returns a representation of the first byte of the string, in this case, the numeric value of the first byte. If you have a look at an ASCII table, you will notice, that the character 1 has the decimal value of 49 there.
If you use Ruby 1.8, you can use either one of these variants:
"123".chars.to_a[0]
# or
"123".chars.first
# or
"123"[0, 1]
I guess you are using Ruby < 1.9. That is the behavior in it. If you want to get what you expect, upgrade to Ruby >= 1.9. Or, if you insist on using Ruby < 1.9, do number[0, 1] instead of number[0].
This is because in Ruby 1.8, String#[] returns the code of the character in that position, e.g. 50 is the ASCII code for 2.
I want to understand a piece of code I found in Google:
i.to_s
In the above code i is an integer. As per my understanding i is being converted into a string. Is that true?
Better to say that this is an expression returning the string representation of the integer i. The integer itself doesn't change. #pedantic.
In irb
>> 54.to_s
=> "54"
>> 4598734598734597345937423647234.to_s
=> "4598734598734597345937423647234"
>> i = 7
=> 7
>> i.to_s
=> "7"
>> i
=> 7
As noted in the other answers, calling .to_s on an integer will return the string representation of that integer.
9.class #=> Fixnum
9.to_s #=> "9"
9.to_s.class #=> String
But you can also pass an argument to .to_s to change it from the default Base = 10 to anything from Base 2 to Base 36. Here is the documentation: Fixnum to_s. So, for example, if you wanted to convert the number 1024 to it's equivalent in binary (aka Base 2, which uses only "1" and "0" to represent any number), you could do:
1024.to_s(2) #=> "10000000000"
Converting to Base 36 can be useful when you want to generate random combinations of letters and numbers, since it counts using every number from 0 to 9 and then every letter from a to z. Base 36 explanation on Wikipedia. For example, the following code will give you a random string of letters and numbers of length 1 to 3 characters long (change the 3 to whatever maximum string length you want, which increases the possible combinations):
rand(36**3).to_s(36)
To better understand how the numbers are written in the different base systems, put this code into irb, changing out the 36 in the parenthesis for the base system you want to learn about. The resulting printout will count from 0 to 35 in which ever base system you chose
36.times {|i| puts i.to_s(36)}
That is correct. to_s converts any object to a string, in this case (probably) an integer, since the variable is called i.