学習日記

学習記録

Rubyで素数判定するプログラムを作成

Ruby素数を判定するプログラムを作ってみる

今日はRubyを使って、素数を判定するプログラムを作ってみようと思います。

要件として

  • 素数はその数値と1以外の数値で割ることのできない数とする
  • 例外として1は素数としないものとする
  • 正数であればどのような数でも素数か判定出来る
  • 異常な値はこないものとする
  • Minitestを使いテストコードも一緒に作成する必要がある

とします。

今回のケースでは先にテストコードを作ったほうが楽そうなので、テストコードから作っていきます。

ではまずどのようなテストケースを作成するかを考えていきます。

今回は簡単に7が正しく素数と判断されるか,10が正しく素数ではないと判断されるか,1を正しく素数ではないと判断できるか

ではテストコードを書いていきます

require 'minitest/autorun'
require '../lib/prime.rb'

class TestClass < Minitest::Test
  def test_prime
    assert_output(stdout = "7は素数です\n" , stderr = nil) { prime?(7) }
    assert_output(stdout = "10は素数ではありません\n" , stderr = nil) { prime?(10) }
    assert_output(stdout = "1は素数に含めません\n" , stderr = nil) { prime?(1) }
  end
end

今回はこのように書いてみました。 もし一緒に作ってみる方がいれば、require先の実行ファイルはご自身の環境に合わせてください。

assert_outputstdoutに期待される標準出力stderrに期待される標準エラー出力を入力します。 ブロックに渡した式が期待されている出力かどうかを評価します。 つまりprime?(x)が実行された時にstdoutと同じ値が返ってくればテストをパスします

stdoutに1を指定された際は、1は自身と1で割り切れるが例外として素数としない数値なので違うメッセージを返すことにします。

それでは実際にプログラムを作っていきます

どのようなプログラムが必要でしょうか?

一旦書き出していこうと思います

  • どの値が素数なのか判断するのに引数が必要
  • 素数かどうかを判断する
  • 素数であれば"xは素数です"と出力する
  • 素数でない場合は"xは素数ではありません"と出力する
  • 1の時は別枠で処理を用意して、"1は素数に含めません"と出力する

簡単に実装できそうなところだけ書いてみます

def prime?(num)
    if num == 1
    puts "1は素数に含めません"
    return
    end
end

とりあえず引数が1だった場合は長々と処理させるのも無駄なので、さっさと処理を抜ける実装にしました。 それでは本格的に実装していきます。

どのようにすれば素数かどうかを判断できるでしょうか? 7をケースに考えてみます。

素数の定義は" 素数はその数値と1以外の数値で割ることのできない数とする"としたので

その数値以上の値であれば絶対に割り切れないことは自明なので7の場合であれば

2,3,4,5,6で割り切れるかどうかを確認していけば素数であるかどうかを判断できそうです。

いくつかその値を出力する方法は考えられますが、今回はdowntoメソッドを使って実装してみます。

(num -1).downto(2) とすれば6から2まで値を1ずつ減らしながら繰り返すという意味を持ちますので、期待通りの動作をしそうです。

ここから持ってきた値を7と割っていけばいいので

def prime?(num)
    if num == 1
    puts "1は素数に含めません"
    return
    end
    (num - 1).downto(2) do |number|
      if num / number # が割り切れる
        puts "#{num}は素数ではありません"
      end
    end
  end

とすればよさそうですね。

割り切れるかどうかの判断ですが、ここは簡単に%演算子で解決できそうです。

後は割り切れなかった場合に素数である旨を出力させれば

def prime?(num)
    if num == 1
    puts "1は素数に含めません"
    return
    end
    (num - 1).downto(2) do |number|
      if num % number == 0
        puts "#{num}は素数ではありません"
      end
    end
    puts "#{num}は素数です"
end

完成!でしょうか?

このままだと最後に絶対に素数である旨が出力されてしまいますね。

素数ではないことが分かったらもうあとは処理をしなくていいので、処理を抜けさせてしまいましょう

def prime?(num)
    if num == 1
    puts "1は素数に含めません"
    return
    end
    (num - 1).downto(2) do |number|
      if num % number == 0
        puts "#{num}は素数ではありません"
        return
      end
    end
    puts "#{num}は素数です"
end

returnを付けることで、メソッドを抜けることが出来ます。

それではテストしてみます

Run options: --seed 23997

# Running:

.

Finished in 0.001881s, 531.6109 runs/s, 1594.8328 assertions/s.

1 runs, 3 assertions, 0 failures, 0 errors, 0 skips

問題なさそうですね。

リファクタリングの余地はありそうですが、今回はこれで完成とします。

お疲れ様でした。