素数かどうかを判定するFunction
素数かどうかを判定するFunction
久しぶりの投稿。
素数かどうかを判定するメソッドを自作してみた。
その前に前回の記事の恥ずかしい誤りを訂正せえよ、と思っていますが。
コード
ごちゃごちゃなしで、書いたコードをぶちまける。
リスト1 標準モジュール
Option Explicit Private Const NOT_NATURAL_NUMBER As String = _ "引数は自然数でなければいけません。" Public Function isPrimeNumber( _ ByVal targetNumber As Long) As Boolean isPrimeNumber = False If targetNumber < 1 Then _ Call Err.Raise(Number:=10001, _ Source:="Arg is not natural number.", _ Description:=NOT_NATURAL_NUMBER) If targetNumber = 1 Then Exit Function If targetNumber = 2 Then GoTo Finalizer '……(*)' Dim turningPoint As Long turningPoint = CLng(targetNumber / 2) Dim i As Long For i = 2 To turningPoint '……(**)' If targetNumber Mod i = 0 Then Exit Function Next Finalizer: isPrimeNumber = True End Function
(*)では、引数が「2
」のときに「True
」を返すように、
If targetNumber = 2 Then GoTo Finalizer
と書いたが、実はこの1行がなくても、「isPrimeNumber(2)
」は「True
」を返す。
引数targetNumber
が「2
」のとき、変数turningPoint
の値はFor
ループの初期値「2
」よりも小さくなるのだが、ステップ実行してみると、(**)の
For i = 2 To turningPoint If targetNumber Mod i = 0 Then Exit Function Next
ループに突入しないのだ。
For
ループの開始値が終了値よりも大きいときにStep
を抜かすとコンパイルエラーになると思い込んでいたので、これは意外だった。
ただ、だからといって(*)を書かないと、後で見たときにわけがわからなくなると思ったので、冗長ではあるが明示しておくことにした。
実験
次のコードで動作確認。
リスト2 標準モジュール
Public Sub testIsPrimeNumber() Dim i As Long For i = 1 To 100 Debug.Print i & vbTab & ":" & isPrimeNumber(i) Next End Sub
こいつを実行すると、
こうなった。
おわりに
素数判定プログラムなんて、太古の昔から先人たちが色んなアルゴリズムを考えて洗練されまくっているだろうから、後で調べてみる。
車輪を再発明した後、既に発明済みの車輪を見て学ぶ、というのは良い方法だと思う。
ちなみに、今回なぜこんなことをしようと思ったのかというと、Twitterで結婚式の祝儀に3万11円を包む、というのを見かけたから。素数ゆえ「割れない」ということで。
この話を同僚にしようとしたものの、「アレ、30011円だっけ? 30001円だっけ?」となったので、「素数かどうかを判定するメソッドを書いてみようか」となったわけ。
30011円だと割れなくて、30001円だと割れる(意外じゃないっすか?)ので、気をつけましょう。