Skip to content

Numbers

Numbers Inheritance Hierarchy

Numbers Inheritance

Numeric is the class from which all higher-level numeric classes should inherit. Classes such as Integer inherit from the Numeric class. Numeric contains methods such as abs, ceil, zero?, negative?, to_int and more.

  • The Integer class is the parent for the Fixnum and BigNum.
  • Fixnum is used for fixed length numbers. BigNum holds numbers that cannot fit in a Fixnum. The conversion happens automatically.
  • Float represent floating-point numbers.
  • Complex represents complex numbers, numbers in the form a+b_i_ where i is an imaginary number.
  • Rational represents rational numbers, numbers in the form a/b.

Creating Numbers

We can create number types from their literal values e,g :

irb(main):098:0> n = 10
=> 10
irb(main):099:0> n.class
=> Integer

We can check what type n is using the class method or using the is_a? method as follows :

irb(main):100:0> n.is_a? Integer
=> true

Or if its a Float type we can use the is_float? :

irb(main):101:0> n.is_a? Float
=> false

Numeric Alterations

Numeric types allows for performing mathematical calculations.

irb(main):105:0> n = 20
=> 20
irb(main):106:0> n = n+ 2
=> 22
irb(main):107:0> n = n / 2.0
=> 11.0
irb(main):108:0> n.class
=> Float
irb(main):109:0> n.is_a? Numeric
=> true

We can also call methods on the numeric types e.g to get the absolute value as follows :

irb(main):111:0> n = -10
=> -10
irb(main):112:0> n.abs
=> 10

Get the ceiling using the ceiling as follows :

irb(main):114:0> n = 10.6
=> 10.6
irb(main):115:0> n.ceil
=> 11

and also the floor using the floor function as follows :

irb(main):117:0> n = 10.6
=> 10.6
irb(main):118:0> n.floor
=> 10

We can also round integer values using the round function as follows :

irb(main):119:0> n = 10.6
=> 10.6
irb(main):120:0> n.round
=> 11

or round down :

irb(main):121:0> n = 10.2
=> 10.2
irb(main):122:0> n.round
=> 10

Numeric Comparison

We can perform numeric comparison using the number class.

>> n = 10
=> 10
>> n == 10
=> true
>> n < 5
=> false
>> n <= 12
=> true
>> n == 10.00
=> true

We can also compare the number using the spaceship operator as follows :

>> 10 <=> 11
=> -1
>> 10 <=> 9
=> 1
>> 10 <=> 10
=> 0

We can check if the two values are equal using the eql? method as follows :

irb(main):123:0> 10.eql? 10
=> true
irb(main):124:0> 10.eql? 10.0
=> false

Check if the values are even or odd as follows :

>> 10.odd?
=> false
>> 10.even?
=> true

Check if the number is between a specific range as follows :

>> 10.between?(3,12)
=> true

We can use the iterators and count up to or down to a specified number as follows :

irb(main):126:0> 1.upto(3) {|n| p n}
1
2
3
=> 1

or going down as follows :

irb(main):127:0> 3.downto(1) {|n| p n}
3
2
1
=> 3

Parsing Numbers

We can get the corresponding number represented as a string :

'400'.to_i       # => 400
'3.14'.to_f      # => 3.14
'1.602e-19'.to_f # => 1.602e-19

The to_i coverts the number to an Integer and the to_f converts the number into a Float. We can also pass in parameters to the methods to specify the base for the to_i method :

'405'.to_i(8)  # 261
'405'.oct      # 261
'405'.hex      # 1029
'405'.to_i(16) # 1029

We can also convert numbers to their corresponding string in binary, octal, or hex as follows :

405.to_s(2)     # 110010101
405.to_s(16)    # 195

You can use the Integer and Float classes to parse and these will throw errors if the string can't be parsed.

Integer('405')          # 405
i = Integer('405ab')    # ArgumentError: invalid value for Integer(): "405ab"
Float('4.5')            # 4.5
Float('4.5f')           # ArgumentError: invalid value for Float(): "4.5f"

The Integer to_s can create a string representation in every integer base. The String to_i can parse a string to a number in a supported base.

"-1001001".to_i(2)  # -73
"abc".to_i(16)      # 2748

-73.to_s(2)         #  "-1001001"
2748.to_s(16)       # 2748

Random Numbers

The rand method is used to generate random numbers. rand returns a pseudo-random floating point number between 0.0 and 1.0, including 0.0 and excluding 1.0.

rand    # 0.7376536979277991
rand    # 0.7906867058221021

If we pass in a value n, it will generate a number between 0 and n - 1.

rand(10) # generates numbers between 0 and 9
rand(5..10) # generates numbers between 5 and 10

Exercise

  1. Create a routine that generates random numbers
  2. Select a random value from a hash. Create an hash, here is a sample :

    ruby m = { key1: 'value1', key2: 'value2', key3: 'value3' } 3. Find the average, median and mode for a set of numbers passed in as an array. Test with the following :

    ruby mean([1,2,3,4]) # => 2.5 4. We have a set of players that participated in different games as follows :

    ruby games = [["Alice", "Bob"], ["Carol", "Ted"], ["Alice", "Mallory"], ["Ted", "Bob"]]

    Write code to only show the unique players that participated. The set of players should not contain duplicates. Expected output should be "Alice", "Mallory", "Ted", "Carol", "Bob" 5. Use the Luhn algorithm to verify a credit card number. More information on how the algorithm works is available on Wikipedia

Solution

  1. They are many ways to to this. Use the rand methods as follows to generate a random number :

    ruby rand(47) # generate a random number bewtween 0 and 47 2. We can first extract the values from the array and then choose each one at random.

    ruby m.values.sample # the values method returns all values as an array m[m.keys.sample] # longer version, get the random key and use it to find a value 3. Here is the sample solution for finding the mean, media and mode.

    ```ruby

    mean

    def mean(array) array.inject(array.inject(0) { |sum, x| sum += x } / array.size.to_f end

    median

    def median(array, already_sorted=false) return nil if array.empty? array = array.sort unless already_sorted m_pos = array.size / 2 array.size % 2 == 1 ? array[m_pos] : mean(array[m_pos-1..m_pos]) end

    def modes(array, find_all=true) histogram = array.inject(Hash.new(0)) { |h, n| h[n] += 1; h } modes = nil histogram.each_pair do |item, times| modes << item if modes && times == modes[0] and find_all modes = [times, item] if (!modes && times > 1) or (modes && times > modes[0]) end modes ? modes[1…modes.size] : modes end

    mean([1,2,3,4]) # => 2.5 median([1,2,3,4,5]) # => 3 modes([1,2,3,4]) # => nil modes([1,1,2,3,4]) # => [1] modes([1,1,2,2,3,4]) # => [1, 2] modes([1,1,2,2,3,4,4]) # => [1, 2, 4] modes([1,1,2,2,3,4,4], false) # => [1] `` 4. We can use theSet` class found in the set standard library. We will need to require it as follows :

    ```ruby require 'set'

    games = [["Alice", "Bob"], ["Carol", "Ted"], ["Alice", "Mallory"], ["Ted", "Bob"]] players = games.inject(Set.new) { |set, game| game.each { |p| set << p }; set } ```

    We can also convert an array to a set using the to_set method. This wil remove duplicates. 5. Many implementations of the algorithm.