Number Conversions in Ruby
Tags: ruby, beginners
Published: 2019-12-04 21:03:07


Beginner rubyists are spoiled while they first learn the language when it comes to type conversions. Ruby has many built in methods for any conversions you could think of, and it allows you to forget about what is actually happening under the hood. I found that even with a strong understanding of ruby syntax, when dealing with floating points I had unexpected results. I'm going to go over simple number conversions in ruby, and then go into some detail on what is actually happening.

### Built in Methods
Ruby offers simple ways to change numbers from the integer class to the floating point class, and back again. Using `to_i`, you can change any number into an instance of the integer class. Likewise, you can use `to_f` to convert any number into a floating point number or float class. Floats include decimal places, and are considered inexact number in ruby. I talk about inexect numbers later on. 

```Ruby
10.0.to_i      #10
10.to_f        #10.0
Integer(10.0)  #10
Float(10)      #10.0
```
Great! You can see that `Integer()` and `Float()` act the same way as `to_i` and `to_f`. Ruby also allows you to change strings to numbers using `to_i`. This is particularly useful if you are receiving input from a user or a document. When there are non-number characters involved, ruby strips characters after the number, and just leaves you the number. If the numbers fall in the middle or after other characters, ruby will not recognize those numbers, and returns 0. Additionally, if a number in a string has a decimal, it will need to be converted to a float to keep those digits.

```Ruby 
"76 Trombones!".to_i    #76
"76 Trombones!".to_f    #76.0
"AB72JP".to_i           #0
"AB72JP".to_f           #0.0
"32 and 48".to_i        #32
"32 and 48".to_f        #32.0
"4.89".to_i             #4
"4.89".to_f             #4.89
76.to_s                 #"76"

``` 

Everything seems to behave as expected when converting from strings, and when converting back to a string, we can just use `to_s`. Let's look at `to_i` again in regards to floats.
```Ruby 
4.8.to_i        #4
4.99999.to_i    #4
```
For floating points, the `to_i` conversion truncates the number, meaning that there is no rounding. Even in the case of 4.99999, it still converts it to 4. What if we want to round to the nearest integer? Ruby has a built in function `round()` which allows us to both change floats to integers, and round floats to decimal places. `round()` with no argument will round to 0 decimals, which will return an integer type number. Using `round(1)` will round to one decimal, and `round(2)` will round to two decimals. 

```Ruby
4.8.round()         #5
4.99999.round(0)     #5
4.325.round(2)      #4.33
4.99999.round(2)    #5.0
4.2.round           #4
```

At this point, I hope you are feeling confident about converting numbers in ruby. Another case of implicit conversions can be in doing math with integers and floats. When you divide two integers using `/`, it will be default return a whole number quotient. If you want the remainder, you can use the modulus, `%`. If you were hoping for a decimal number, then you will need to have at least one floating point number in the operation.

###Ruby Math

```Ruby
17/4            #4
17%4            #1
17.0/4          #4.25
17/(4.to_f)     #4.25
(17/4).to_f     #4.0
```
Make sure that you convert to float _before_ you divide, otherwise you will end up with the wrong results. I mentioned earlier that float type numbers are _inexact_. This makes doing more complicated math difficult using floats. Let's look at an example where this is going to effect your code.

```Ruby
b = 1 - 0.9         #0.09999999999999998
a = 0.1             #0.1
a == b              #false
0.4 + 0.2           #0.6000000000000001
```
Why did `1 - 0.9` not equal `0.1`? This is the inexactness of floats. Becuase of how they are stored, when using them for math, you start to build up errors in the numbers. What is the alternative to using floats? In Ruby, you can use a class called BigDecimal. This is part of Ruby, but you will need to add `require "BigDecimal"` to the top of your code.
```Ruby
require "BigDecimal"

BigDecimal("76582.124") #0.76582124e5
b = BigDecimal("0.9")   #0.9e0
a = BigDecimal("1.0")   #0.1e1
c = 0.1
(a - b) == c            #true

(a - b)                 #0.1e0
(a - b).to_f            #0.1
```

With BigDecimal, numbers are stored in scientific notation, where the e represents the decimal times 10 to the power after the e. This allows you to work to a precision that isn't available when using floats. 

Hopefully this guide helped you understand ruby number more easily. There are many other nuances you will encounter, but this is a good starting point for most projects.