-1

I'm confused about the optional argument for to_i. Specifically, what "base" means, and how it impacts the method in this example:

"0a".to_i(16) #=> 10

I have trouble with the optional argument in regards to the string the method is called on. I thought that the return value would just be an integer value of 0.

sawa
  • 165,429
  • 45
  • 277
  • 381
Nano
  • 1
  • Base 16 is also known as hexadecimal. 0a is a hexadecimal number. – Ry- Feb 07 '19 at 06:37
  • 1
    There is nothing Ruby-specific or even programming-specific about this. It is just the normal standard meaning of the word "base", in other words, it's just middle school level maths. – Jörg W Mittag Feb 07 '19 at 07:40
  • Exactly as Jorg W Mittag says. And often, it is elementary school level math for some students. – sawa Feb 07 '19 at 10:35

1 Answers1

4

Simple answer: It's because 0a or a in Hexadecimal is equal to 10 in Decimal.

And base, in other word Radix means the number of unique digits in a numeral system.

In Decimal, we have 0 to 9, 10 digits to represent numbers.
In Hexadecimal, there're 16 digits instead, apart from 0 to 9, we use a to f to represent the conceptual numbers of 10 to 15.

You can test it like this:

"a".to_i(16)
#=> 10
"b".to_i(16)
#=> 11
"f".to_i(16)
#=> 15
"g".to_i(16)
#=> 0  # Because it's not a correct hexadecimal digit/number.
'2c'.to_i(16)
#=> 44
'2CH2'.to_i(16)
#=> 44  # Extraneous characters past the end of a valid number are ignored, and it's case insensitive.
9.to_s.to_i(16)
#=> 9
10.to_s.to_i(16)
#=> 16

In other words, 10 in Decimal is equal to a in Hexadecimal.
And 10 in Hexadecimal is equal to 16 in Decimal. (Doc for to_i)

Note that usually we use 0x precede to Hexadecimal numbers:

"0xa".to_i(16)
#=> 10
"0x100".to_i(16)
#=> 256

Btw, you can just use these representations in Ruby:

num_hex = 0x100
#=> 256
num_bin = 0b100
#=> 4
num_oct = 0o100
#=> 64
num_dec = 0d100
#=> 100

Hexadecimal, binary, octonary, decimal (this one, 0d is superfluous of course, just use in some cases for clarification.)

Til
  • 5,150
  • 13
  • 26
  • 34
  • 1
    Nice explanation! Above will work with case insensitivity & continue to take characters till it get invalid character e.g. '2CH2' will take '2C' in to account. – ray Feb 07 '19 at 06:56
  • @ray Thanks, added it to the examples :) – Til Feb 07 '19 at 07:07
  • Thank you for the in-depth explanation, @Tiw! I've learned something new today. – Nano Feb 07 '19 at 08:43
  • I understand how we get #=> 256 from ("0x100".to_i(16)), but how could we interpret this in a simple way? Also, is there any reason why '0x' proceeds Hex numbers? – Nano Feb 07 '19 at 09:03
  • 1
    It's a convention... `0x` indicate you want to use an Hex number. [HERE](https://stackoverflow.com/questions/2670639/why-are-hexadecimal-numbers-prefixed-with-0x) an explanation – Nifriz Feb 07 '19 at 09:04
  • @Nano `0x100 => 1 * 16^2`. he**x**adecimal, **b**inary, **o**ctonary, so we use `0x`, `0b` and `0o`. – Til Feb 07 '19 at 09:06
  • 1
    @Nano: There is no specific reason. The standard way to write it is to attach the base as a subscript postfix or prefix. However, most programming languages don't support subscript (the only one I can remember off the top of my head is Fortress). Therefore, some languages use parentheses (e.g. `1234DEADBEEF(16)`) or underscores (`1234DEADBEEF_16`). But prefixes are also common, e.g. `0x` for 16, `0o` for 8, `0b` for 2, `0d` for 10. In Ruby, octal numbers can also be prefixed with the number `0`, i.e. `10` is 10 decimal, but `010` is 8 decimal, and `0x10` is 16 decimal, `0b10` is 2 decimal. – Jörg W Mittag Feb 07 '19 at 14:09