Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Rubyで学ぶ実用数学:モジュロ演算子、進数変換、ビットマスクの基礎

優れたプログラマーになるためには、数学の知識が必要なのでしょうか?

答えは「場合によります」。

もし日々CRUDアプリの作成だけを行うのであれば、数学の知識はほとんど必要ないかもしれません。しかし、もっと面白いことに挑戦したい方——例えばコーディングチャレンジに取り組んだり、プログラミング面接に備えたりしたい方にとっては、いくつかの基本的な概念を身につけておくことが大きな助けになります。

この記事で学べる内容

  • モジュロ演算子(%
  • 記数法(数体系)
  • ビットマスキング

これらの概念をRubyでどう活用するかを解説する、実践的なガイドです。それでは始めましょう!

Rubyのモジュロ演算子(%)とは

Rubyのモジュロ演算子は次のように表記します。

%

そう、パーセント記号と同じ形です。

では、これは何をするものでしょうか?

モジュロ演算子は割り算の余りを求める演算子です。これを使うと、「ある数が偶数か奇数か」の判定などが可能になります。

実際、Rubyにはeven? / odd?という便利なメソッドが用意されています。

8.even?
# true

5.even?
# false

しかし、「3で割り切れるか」のような判定には、モジュロ演算子を使う必要があります。

9 % 3 == 0
# true

それでは、さらに多くの活用例を見ていきましょう。

モジュロ演算子の実践的な使い方

モジュロ演算子を使うと、ある数が別の数で割り切れるかどうかを判定できます。

割り算の余りが0であれば、その数は割り切れるということです。

有名なコーディング課題「FizzBuzz」では、ある数が3または5で割り切れるかどうかを判定します。

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

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

また、モジュロ演算子を使えば「N回ごとに何かを実行する」という処理も簡単に書けます。

たとえば

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

あるいはstepメソッドを使っても同じことができます。

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

divmodメソッドの活用

モジュロ演算のもう一つの応用例として、「分」を「時間+残りの分」に変換する処理があります。

90分は「1時間30分」と同じです。

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

注目してほしいのはdivmodメソッドです。

このメソッドは、割り算(商)とモジュロ(余り)を同時に計算してくれます。

とても便利ですね!

記数法(数体系)を理解する

記数法とは、数を表現するための仕組みのことです。

日常的には10進法を使っています。

0123456789

記数法は、数字(場合によっては文字も含む)の集合によって構成されます。

たとえば

16進法では合計16種類の記号を使用します。

0123456789abcdef

以下は主な記数法の一覧表です。

名称 記号の数(基数) 使用する記号
16進法(ヘキサデシマル) 16 0123456789abcdef
10進法(デシマル) 10 0123456789
8進法(オクタル) 8 01234567
2進法(バイナリ) 2 01

Rubyではto_sメソッドを使って、記数法同士の変換ができます。

ここでは10進数9)から2進数1001)への変換方法を紹介します。

9.to_s(2)
# "1001"

逆に、文字列に対してto_iメソッドを使えば整数へ戻せます。

つまり、16進数ff)から10進数255)への変換は次のように書けます。

"ff".to_i(16)
# 255

引数の16は、その記数法の「記号の数」、つまり基数を意味しています。

ビットマスキングとは?

普段の生活で「できるだけ少ない容量に大量の真偽値(boolean)を詰め込みたい」と考えることは、おそらくないでしょう。

しかし、もしそういう場面に遭遇したら……

そんなときに役立つ強力なテクニックが「ビットマスキング」です。

ビットマスキングを使えば、大量の真偽値を1つの整数値にまとめて格納できます。

なぜそんなことが可能なのでしょうか?

それは、整数が個々のビットの集まりで構成されているからです。

1つの真偽値は1ビットで表現でき、Rubyの整数は64ビットを持つため、最大64個の真偽値を1つの数値に詰め込むことができます。

ここで活躍するのがビット演算子です。

一覧表はこちら

名称 記号 用途
XOR(排他的論理和) ^ ビットの反転(トグル)
AND(論理積) & ビットの確認
NOT(否定) ~ ビットのクリア
OR(論理和) | ビットのセット

ビット演算子はBIT(ビット)レベルで動作するため、まさに私たちが求めている機能です。

コード例はこちら

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

ビットマスキングの使い方

これでsetclearcheckメソッドを使って、このデータ構造を操作できるようになりました。さらに、各ビットが何を意味するのかを定数として定義しておくと分かりやすくなります。

class Bitmask
  ENGINES_ENABLED = 1
  CAPTAIN_ABOARD  = 2
  SHIELDS_UP      = 4

  # ... 残りのコード
end

bit = Bitmask.new

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

setに渡せる有効な値は「1と2のべき乗」(2, 4, 8, 16, 32…)です。こうすることで、他のビットを誤って上書きすることを防げます。

たとえば64 + 32 + 1を格納した場合、内部の値は次のようになります。

1100001

Rubyの便利な数学系メソッド

Rubyには、役立つ組み込みの数学メソッドがいくつか用意されています。

すでに紹介したdivmodeven?odd?以外にも、以下のようなものがあります。

  • ** / pow(べき乗計算)
  • gcd(最大公約数)
  • abs(絶対値。マイナス符号を取り除く)
  • round(四捨五入して最も近い整数に丸める)
  • floor & ceil(切り下げ / 切り上げ)
  • Math.sqrt(n)(nの平方根)
  • Math.log2(n)(nのlog2)
  • digits(整数を桁ごとの配列に変換。順序は逆順)

使用例

5 ** 2
# 25

-10.abs
# 10

300.digits
# [0, 0, 3]

まとめ

この記事では、モジュロ演算子%を使って割り算の余りを求める方法や、その余りを利用して「割り切れるかどうか」を判定するテクニックを学びました。

また、記数法(数体系)、ビットマスキング、そしてビット演算子についても理解を深めることができました。

これらの知識は、コーディング試験やアルゴリズムの問題に取り組む際にきっと役立つはずです。
ぜひこの記事を参考に、Rubyでの数学的な処理をマスターしてください。

  1. Rubyでパーサーを自作する方法!StringScannerを使った実装手順を徹底解説

    パース(構文解析)とは、文字列の集まりから意味を読み取り、プログラムが扱える形のデータへと変換する技術です。正規表現でも文字列の解析は可能ですが、すべての場面に適しているわけではありません。 たとえば、正規表現でHTMLを解析するのはあまり良い方法ではないというのは、プログラミング界隈ではよく知られた話です。 Rubyにはnokogiriという強力なライブラリがあり、HTMLの解析はこれに任せられます。しかし、自分でパーサーを一から作ってみると、文字列処理や構文解析の仕組みについて多くのことを学べます。それでは早速始めていきましょう! Rubyでのパースの基本:StringScannerクラス

  2. Rubyの文字列フォーマット入門:%演算子と書式指定子の使い方

    この記事では、Rubyで文字列をフォーマットする方法について詳しく解説します。 なぜ文字列のフォーマットが必要なのでしょうか?例えば、10未満の数値にも先頭にゼロを付けて表示したい場合(01、02、03など)、あるいはコンソール出力を見やすいように桁を揃えて整形したい場合などが挙げられます。 他の言語ではprintf関数を使って文字列をフォーマットできます。C言語を使ったことがある人なら馴染み深いでしょう。printfでは、書式指定子(フォーマット指定子)のリストと、変数や値のリストを定義して使用します。 Rubyでの文字列フォーマットの基本 Rubyでもsprintfメソッドが利用可能ですが