RubyGuides
Share this post!

Helpful Math Concepts For Ruby Developers

Let’s talk about Math in Ruby.

Do you need to know math to become a good programmer?

It depends!

If you’re just going to be writing CRUD apps all day then you probably don’t need to know much math, if any.

But if you want to do more interesting things, like solving coding challenges & be prepared for coding interviews then learning a few basic concepts can be helpful.

Today you’re going to learn about:

  • The modulo operator
  • Number systems
  • Bitmasking

You’ll learn how to apply these concepts in Ruby, so this is going to be a practical guide.

The Modulo Operator

The Ruby modulo operator looks like this:

%

Yes, just like the precentage symbol.

What does it do?

It gives you the remaining of a division.

This can be used for things like checking if a number is even or odd.

In Ruby, we have the even?/odd? methods.

Example:

8.even?
# true

5.even?
# false

But if you want to check if a number is divisible by 3, then you have to use the modulo operator.

Example:

9 % 3 == 0
# true

Practical Uses For The Modulo Operator

You can use the modulo to check if a number is divisible by another.

A number is divisible if the remaining is 0.

Example:

The classic “FizzBuzz” coding challenge wants you to find out if a number is divisible by 3 or 5.

if n % 3 == 0
  puts "Fizz"
end

if n % 5 == 0
  puts "Buzz"
end

You can use the modulo operator to do things every Nth time.

Like this:

(1..10).select { |n| n % 2 == 0 }
# [2, 4, 6, 8, 10]

Or you can use the step method:

(2..10).step(2).to_a
# [2, 4, 6, 8, 10]

Another use for the modulo operator is to convert minutes to hours + remaining minutes.

Example:

We have 90 minutes, which is the same as 1 hour & 30 minutes.

hours, minutes = 90.divmod(60)
# [1, 30]

Notice the divmod method:

It does division & modulo (the remaining of the division) at the same time.

Understanding Number Systems

A number system is a way to represent numbers.

In your daily use of numbers you use the decimal system.

0123456789

A number system is composed of a set of numbers & sometimes characters too.

For example:

The hexadecimal system uses 16 symbols in total.

0123456789abcdef

Here’s a table of common numeric systems:

Name Symbol Count Symbols
Hexadecimal 16 0123456789abcdef
Decimal 10 0123456789
Octal 8 01234567
Binary 2 01

You can convert between number systems in Ruby with the to_s method.

Here’s how to convert from decimal (9) to binary (1001):

9.to_s(2)
# "1001"

You can use the to_i method on a string to convert back into an integer.

So if you want to go from hexadecimal (ff) to decimal (255) you can do this:

"ff".to_i(16)
# 255

Where 16 is the “symbol count” or base for the number.

What is Bitmasking?

You probably don’t wake up every day thinking…

“Hey! I need to pack a lot of boolean values into as little space as possible.”

But if someday you need to do that…

A great technique that can help you is “bitmasking”.

With bitmasking, you can pack a lot of boolean values into a single integer value.

How is that possible?

By using the individual bits that the number is made of.

Because a boolean value can be represented by a single bit, and an integer value has 64 bits, we can pack up to 64 boolean values into a single number.

We are going to use bitwise operators.

Here’s a table:

Name Symbol Use
XOR (Exclusive OR) ^ Toggle Bit
AND & Check Bit
NOT ~ Clear Bit
OR | Set Bit

Bitwise operators work at the BIT level & that’s exactly what we want.

Here’s a code example:

class Bitmask
  def initialize
    @value = 0
  end

  def set(bit)
    @value |= bit
  end

  def clear(bit)
    @value &= ~bit
  end

  def check(bit)
    (@value & bit) == bit
  end

  def to_binary
    @value.to_s(2)
  end
end

bit = Bitmask.new

Now you can use the set, clear & check methods to work with this data structure. You may also want to define constants to describe what each value means.

Example:

class Bitmask
  ENGINES_ENABLED = 1
  CAPTAIN_ABOARD  = 2
  SHIELDS_UP      = 4

  # ... rest of code here
end

bit = Bitmask.new

bit.set(Bitmask::ENGINES_ENABLED)
bit.check(Bitmask::ENGINES_ENABLED)

Valid values for set include 1 & the powers of 2 (2,4,8,16,32…), this avoids overwriting other bits.

Powers Of Two

If we have 64 + 32 + 1, the stored value will look like this:

1100001

Ruby Math Methods

Ruby includes a few built-in math methods that can be helpful.

We already covered divmod, even? & odd?.

Other methods include:

  • ** / pow (exponentiation)
  • gcd (greatest common divisor)
  • abs (absolute value, removes negative sign)
  • round (round to closest integer)
  • floor & ceil (round down / round up)
  • Math.sqrt(n) (square root of n)
  • Math.log2(n) (log2 of n)
  • digits (converts integer into a reverse array of digits)

Examples:

5 ** 2
# 25

-10.abs
# 10

300.digits
# [0, 0, 3]

Summary

You’ve learned a few interesting math tricks, like using modulo % to find out the remainder of a division. You can use the remainder to check if a number is divisible by another.

You’ve also learned about number systems, bitmasking & bitwise operators.

Don’t forget to share this post…

Leave a comment with your questions & feedback, and to subscribe to the RubyGuides newsletter if you haven’t yet!

Leave a Comment:

4 comments
bedawang says a couple of months ago

very good article! learned some new things, as always.
One remark, isn’t it more convenient to use :

puts “Fizz” if (n%3).zero?

instead of

if n % 3 == 0
  puts "Fizz"
end

Reply
    Jesus Castello says a couple of months ago

    It is, but I don’t like the parenthesis. Just a style choice 🙂

    Reply
Victory says a couple of months ago

300.digits is only available for Ruby >= 2.4.0.

Reply
    Jesus Castello says last month

    Yes! You’re correct, thanks for sharing 🙂

    Reply
Add Your Reply