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_output
はstdout
に期待される標準出力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
問題なさそうですね。
リファクタリングの余地はありそうですが、今回はこれで完成とします。
お疲れ様でした。