• 締切済み

素数を求めるマクロを

走らすと暴走したようになり、素数=151で止まります。 どこが悪いのでしょうか。正常に終わるようにしたいです。 ====================== Sub 素数を求める()   Dim i As Long   Dim j As Long   Dim m As Long   Dim p As Long   Dim flg As Boolean   i = 1   j = 1   p = 2   Do     flg = False     For m = 2 To Int(Sqr(p))       If p Mod m = 0 Then         flg = True         Exit For       End If     Next     If flg = False Then       Cells(i, j) = p       i = i + 1       If i > Rows.Count Then         i = 1         j = j + 1       End If     End If     p = p + 1   Loop End Sub ======================

noname#242965
noname#242965

みんなの回答

  • f272
  • ベストアンサー率46% (7999/17101)
回答No.4

#1 & #3です。 > 次に np=1000000+00をやったら > デバッグとか言って黄色い行ラインが出てくるがこれを正しく > 修正すると、走るのではないか? これは,そんなに大きなnpを使うとは思わなかったので,1列に書けるだけしか領域を確保していないためです。コードの最後の方にある Range("A1").Resize(j) = pp を If j > Rows.Count Then j1 = Int(j / Rows.Count) j2 = j Mod Rows.Count ReDim pp1(Rows.Count, j1) As Long For k = 0 To j1 - 1 For j = 0 To Rows.Count - 1 pp1(j, k) = pp(j + k * Rows.Count, 0) Next j Next k Range("A1").Resize(Rows.Count, j1) = pp1 ReDim pp2(j2, 0) As Long For j = 0 To j2 - 1 pp2(j, 0) = pp(j + j1 * Rows.Count, 0) Next j Range("A1").Offset(, j1).Resize(j2) = pp2 Else Range("A1").Resize(j) = pp End If に変えると動きます。私のいつも使うPCだと35秒くらいで5,761,455番目の素数である99,999,989を出力します。 > 何故まったく同じ結果となったかわからない。 アルゴリズムは違っても同じ結果を返すマクロなのだから当然ですよ。

  • f272
  • ベストアンサー率46% (7999/17101)
回答No.3

#1です。 ついでに言っておくと,アルゴリズムは正しいのだけれど効率は非常に悪い。 セルにアクセスする回数は極力減らすことが速度向上のためには大事なことです。また,pを2から1づつ増やすのは効率が悪い。奇数は素数でないことは明らかなのだからコードの中で明示的に省いておくべきです。そうすると Sub 素数を求める3() Dim np As Long np = 1000000 'これが調べる最大の数 Dim i As Long Dim m As Long Dim p As Long Dim flg As Boolean Dim s As Variant ReDim pp(np, 1) As Long s = Timer pp(0, 0) = 2 i = 1 p = 3 Do flg = False For m = 3 To Int(Sqr(p)) Step 2 If p Mod m = 0 Then flg = True Exit For End If Next If flg = False Then pp(i, 0) = p i = i + 1 End If p = p + 2 Loop Until p > np Range("A1").Resize(i) = pp MsgBox "Elapse time=" & Timer - s End Sub こんな感じになる。でももっといいのはエラトステネスの篩を使って判断することでしょう。そうすると Sub 素数を求める4() Dim np As Long np = 10000000 'これが調べる最大の数 Dim i As Long Dim j As Long Dim k As Long ReDim p(np) As Boolean ReDim pp(np, 1) As Long Dim s As Variant s = Timer For i = 0 To np - 1 p(i) = True Next i p(0) = False For i = 2 To Int(Sqr(np)) + 1 k = Int(np / i) For j = 2 To k If (p(i * j - 1)) Then p(i * j - 1) = False End If Next j Next i j = 0 For i = 0 To np - 1 If (p(i)) Then pp(j, 0) = i + 1 j = j + 1 End If Next i Range("A1").Resize(j) = pp MsgBox "Elapse time=" & Timer - s End Sub こんな感じになる。

noname#242965
質問者

お礼

上のマクロで np=1000000+0 で664579番目(9999991)をたたき出した。 下のエラトステネス篩では np=10000000で664579番目(9999991)をたたき出した。 何故まったく同じ結果となったかわからない。 np=npだから?しかしエラトステネスの篩は早いんじゃないのかな。 結果は同じでもタイムはエラトステネスが早かったのか? も少し、調べてみます。 貴方のアイコンは”数学”カテゴリーでもよく見ます。昔から。 とにかく、マクロを教えてくれてありがとう。感謝です。

noname#242965
質問者

補足

上の方のマクロ np=1000000 t=0.796875って1秒もたってないのか? 78498番目(999983) をたたき出す。 この辺のマクロでタイマーは必須。 次に np=1000000+00をやったら デバッグとか言って黄色い行ラインが出てくるがこれを正しく 修正すると、走るのではないか? 下のマクロはまだやってない。 エラトステネスの篩はその分早くなるはずだが。

  • HohoPapa
  • ベストアンサー率65% (454/690)
回答No.2

暴走しているのではなく 画面のリフレッシュが追いつかない可能性を疑います。 適当なサイクルで  DoEvents を実行すれば、結果なり、変数が オーバーフローするまで実行し続けると思います。 Sub 素数を求める()   Dim i As Long   Dim j As Long      途中略        p = p + 1     If i Mod 1000 = 0 Then      DoEvents     End If   Loop End Sub

  • f272
  • ベストアンサー率46% (7999/17101)
回答No.1

doループから脱出する条件がないので,無限に計算をし続けて暴走します。 最低でも Loop を例えば Loop Until p > 10000 のように確実に止まるようにしましょう。

noname#242965
質問者

お礼

こんにちは。 =========================== Loop Until p > 10000について =========================== Loop Until p > 100000000を設定したら不可となった。 暴走状態になった。 当然だが原因があるので、それらを解決させると可能となるかもしれない。 しかたないので Loop Until p > 10005000を設定したら 664884番目(10004983)をたたき出した。 次に Loop Until p > 10055000を設定したら 668029番目(10054997)をたたき出した。 しかし、これ以上はやっていない。 偶数も計算させている割には意外と速度は速い。 面白い。面白い。

noname#242965
質問者

補足

こんにちは。 10000を設定しましたら、1229番目:9973まで行きました。 10万とか100万とか1億とか、どこまで可能なのか? いずれ、フリーズする場面がまた、出てくるものと予想されます。 やってみます。面白いですね。

関連するQ&A

  • vba boolean変数を開放する方法

    エクセルのセルに「○○○○○○○○○○××××××××××」と入っているものをランダムに並べ代えるマクロを探してみました。 Sub macro2() Dim i, m As Integer Dim b, c As String Dim flg(1 To 20) As Boolean b = Cells(1, 1).Value Randomize For i = 1 To 20 Do m = Int(20 * Rnd + 1) If flg(m) = False Then flg(m) = True Exit Do End If Loop c = c & Mid(b, m, 1) Next i Cells(1, 2).Value = c End Sub これはうまく動くのですが、10行分やろうとして、以下のように変更すると暴走(終わらない)します。 Sub macro2() Dim i, m, n As Integer Dim b, c As String Dim flg(1 To 20) As Boolean For n = 1 To 10 b = Cells(n, 1).Value Randomize For i = 1 To 20 Do m = Int(20 * Rnd + 1) If flg(m) = False Then flg(m) = True Exit Do End If Loop c = c & Mid(b, m, 1) Next i Cells(n, 2).Value = c next n End Sub 一行目が終わってもboolean変数の値がそのまま残っているのが原因らしいのですが開放する方法がわかりません。 取りあえずもう一つマクロを追加してやりたいことはできたのですが、 Sub macro1() Dim n As Integer For n = 1 To 10 Call macro2(n) Next n End Sub Sub macro2(n As Variant) 以下略 なんかスッキリしません。 boolean変数を開放し、マクロひとつですます方法を教えて頂きたくお願いします。 flg(m) = Falseを挿入してもダメでした。

  • 下記のマクロは

    E列の5行目から2000行までの間で 鉄、銅、銀、空白以外の文字が入っていたら 『鉱1_Click』という別のマクロを行うというマクロなのですが、 『銀』に限ってはE列5行目~2000行の間に1つだけあっても 『鉱1_Click』を走らせるようにしたいのですが、 どのように改造すればできると思いますか? Private Sub 鉱_Click() Dim ColumnA Dim flg As Boolean flg = False ColumnA = Columns("E:E") For i = 5 To 2000 If ColumnA(i, 1) = "鉄" Or ColumnA(i, 1) = "銅" Or ColumnA(i, 1) = "銀" Or ColumnA(i, 1) = "" Then Else flg = True Exit For End If Next If flg Then 鉱1_Click Else End If End Sub

  • いま以下のコードでA列のデータから1を探してその

    1つ前と2つ前のB列の値をC.D列に出力することができるのですが、この時のデータ数を知りたいのですがどうすればいいでしょうか? Sub sample() Dim i As Long, j As Long, flg As Boolean For i = 2 To Cells(Rows.Count, 1).End(xlUp).Row If Cells(i, 1) = 0 Then flg = True ElseIf Cells(i, 1) = 1 And flg = True Then j = j + 1 Cells(j, "BT") = Cells(i - 1, "BS") Cells(j, "BU") = Cells(i - 2, "BS") flg = False Else: flg = False End If Next End Sub これでC1とD2に対応するB?とB?の間のデータ数がE1に、C2とD3に対応するB?とB?の間のデータ数がE2にC3と・・・ という具合です。 わかりにくくてすみません。よろしくお願いします。

  • VBAのDoEventsが上手く動きません

    お世話になります。 ExcelのVBAで印刷処理をしているのですが、印刷枚数が多いのでDoEventsイベントを入れ、印刷中断処理を行いたいのですが、上手くできません。 印刷中ダイアログが表示されるのが原因なのでしょうか?それともコードの書き方が悪いのでしょうか?よろしくお願いします。 コードは以下のとおりです。 ************************************************ Public Can_flg As Boolean ************************************************ Private Sub CommandButton1_Click()   Can_flg = True End Sub ************************************************ Private Sub UserForm_Activate()   Dim ms As String   Dim j As integer   Can_flg = False   For j = 1 To 31    DoEvents    If Can_flg = True Then      ms = MsgBox("印刷を中止します。", vbOKCancel)        If ms = vbOK Then         Exit For        Else         Can_flg = False        End If    End If    Me.Label1.Caption = "印刷中です… (" & j & "/" & i & "ページ)"    Sheets("テスト").PrintOut   Next j   Unload Me End Sub

  • マクロで分岐をさせる方法

    下記の記録マクロでWith→End With 間にIFで分岐を試みたのですが エラーになります。どうすれば出来るのか伝授をお願いします。 マクロは初心者です。 Dim hensuh(2) As Integer Dim dekiru As Long Dim kinek As Long Dim uineu As Long Dim myTime As Date Dim flg As Boolean Sub OnTimeSamp1() Application.OnTime EarliestTime:=TimeValue("09:00:00"), Procedure:="Ontime_Set" '記録開始 Application.OnTime EarliestTime:=TimeValue("11:00:00"), Procedure:="Ontime_Reset" '記録終了 End Sub Sub Ontime_Set() 'トグルになっている If flg = False Then flg = True myTime = Now + TimeSerial(0, 0, 1) ElseIf flg = True Then flg = False Else Exit Sub End If If Range("A1").Value = "" Then Range("A1").Value = Format(Now, "hh:mm:ss") '時間記録(スタート) End If Application.OnTime EarliestTime:=myTime, _ Procedure:="my_Procedure", Schedule:=flg If flg = False Then myTime = 0 End If End Sub Sub my_Procedure() Worksheets("kirokuyou").Activate 'ワークシートをアクティブにする。(記録中別のワークシートを開けた場合そこに記録されてしまうのを防ぐ) With Range("A65536").End(xlUp).Offset(1) .Value = Format(Now, "yyyy:mm:dd:hh:mm:ss") '時間記録 .Offset(, 1).Value = Range("S3").Value 'S3 の値 .Offset(, 2).Value = Range("T3").Value 'T3 の値 .Offset(, 3).Value = Range("U3").Value 'U3 の値 .Offset(, 4).Value = Range("V3").Value 'V3 の値 dekiru = Range("V3").Value Range("V6").Value = dekiru kinek = Range("T22").Value Range("T18").Value = kinek uineu = Range("U22").Value Range("U18").Value = uineu 'IF S17 >= 120 Then 'hensuh(0) = Range("S17").Value ←変数に代入後、分岐させたいのですがエラーになる 'Elseif S17 >= 110 Then 'hensuh(1) = Range("S17").Value ←変数に代入後、分岐させたいのですがエラーになる 'Elseif S17 >= 100 Then 'hensuh(2) = Range("S17").Value ←変数に代入後、分岐させたいのですがエラーになる 'End If flg = False myTime = 0 End With Call Ontime_Set End Sub Sub Ontime_Reset() 'タイマーリセット On Error Resume Next Application.OnTime EarliestTime:=myTime, _ Procedure:="my_Procedure", Schedule:=False If Err.Number > 0 Then MsgBox "OnTime設定はされていません。", 64 Err.Clear flg = False Else MsgBox myTime & "の設定は解除されました。", 64 flg = False myTime = Empty End If End Sub

  • 検索 マクロ

    本を見ながら作ったのですが 検索してくれるのですが A列を検索してくれるのですが検索したいのは B列の4番目から下にあるだけ検索したいのですが どういじればいいのでしょうか? Option Explicit Private lastRow As Long Private Index As Integer Private Sub UserForm_Activate() Dim i As Long lastRow = Worksheets("顧客情報").Cells(Rows.Count, 1).End(xlUp).Row + 1 If lastRow <= 3 Then MsgBox "データがありません。" Exit Sub End If For i = 3 To lastRow 名前リストボックス.AddItem Cells(i, 1) Next End Sub Private Sub 検索ボタン_Click() Dim searchName As String searchName = 検索名前テキストボックス.Text If searchName = "" Then MsgBox "検索する名前を入力してください。" Else Dim i As Long Dim no As Long For i = 0 To 名前リストボックス.ListCount - 1 If 名前リストボックス.List(i) = searchName Then no = i 名前リストボックス.ListIndex = no Exit For ElseIf i >= 名前リストボックス.ListCount - 1 Then MsgBox "該当なし。" Exit For End If Next Index = no + 3 Rows(Index).Select End If End Sub

  • 【エクセルマクロ】画像挿入について教えてください。

    Excel2010で下記マクロを実行し、 画像挿入元のフォルダ名を変更・削除したり、メールに添付して送信したりすると「リンクされたイメージを表示できません。ファイルが移動または削除されたか、名前が変更された可能性があります。リンクに正しいファイル名と場所が指定されていることを確認してください。」 と表示されます。 Excel2010では、Shapes.Addメソッドを使用するとリンク解除ができるとのことで、 初心者ながら色々試してみたのですが、うまくいきません。 マクロ初心者のため、詳しく教えていただけると大変助かります。 Private Sub Del_Btn_Click() 指定セル範囲 = "C18:K500" With ActiveSheet Set セル範囲 = .Range(指定セル範囲) For Each 図形 In .Shapes If 図形.Type = msoPicture Then Set 共有セル範囲 _ = Intersect(Range(図形.TopLeftCell, 図形.BottomRightCell), セル範囲) If Not (共有セル範囲 Is Nothing) Then 図形.Delete End If End If Next End With End Sub Private Sub Ins_Btn_Click() Dim fName As Variant Dim i As Long Dim j As Integer Dim k As Integer Dim Pict As Picture Const z1 As Long = 246 'サイズ指定 Const z2 As Long = 184 'サイズ指定 Dim z3 As Long '上位置 z3 = 306 k = 1 fName = Application.GetOpenFilename("JPGファイル, *.jpg", MultiSelect:=True) If IsArray(fName) Then Application.ScreenUpdating = False '配列に格納されたファイル名をソート BubbleSort fName, True 'If UBound(fName) >= 19 Then ' j = 19 ' Else j = UBound(fName) 'End If For i = 1 To j Set Pict = ActiveSheet.Pictures.Insert(fName(i)) If i Mod 6 = 5 Then z3 = z3 + 18.5 - k k = k + 0.5 End If If i Mod 2 = 1 Then With Pict .Width = z1 '横型 .Height = z2 '縦型 .Top = z3 + 146.5 * (i - 1) '上位置 .Left = 83 '左位置 .Locked = False ico = ico + z1 + 10 '間隔指定 End With Else With Pict .Width = z1 '横型 .Height = z2 '縦型 .Top = z3 + 146.5 * (i - 2) '上位置 .Left = 350 '左位置 .Locked = False ico = ico + z1 + 10 '間隔指定 End With End If ActiveCell.Offset(2, 0).Activate Application.StatusBar = "処理中:" & i & "/" & UBound(fName) & "枚目" Next i End If With Application .StatusBar = False .ScreenUpdating = True End With Set Pict = Nothing If i > 0 Then MsgBox j & "枚の画像を挿入しました", vbInformation End If End Sub '値の入替え Public Sub Swap(ByRef Dat1 As Variant, ByRef Dat2 As Variant) Dim varBuf As Variant varBuf = Dat1 Dat1 = Dat2 Dat2 = varBuf End Sub '配列のバブルソート Public Sub BubbleSort(ByRef aryDat As Variant, _ Optional ByVal SortAsc As Boolean = True) Dim i As Long Dim j As Long For i = LBound(aryDat) To UBound(aryDat) - 1 For j = LBound(aryDat) To LBound(aryDat) + UBound(aryDat) - i - 1 If aryDat(IIf(SortAsc, j, j + 1)) > aryDat(IIf(SortAsc, j + 1, j)) Then Call Swap(aryDat(j), aryDat(j + 1)) End If Next j Next i End Sub どうぞよろしくお願いいたします。

  • 抜き出しマクロ(3)

    以下のプログラムは10行ごとにデータを抜き出すプログラムです。 これに追加して、普段は10行に1個データを抜き出し、前回の結果より絶対値が10増減があったとき、 相対値が10%の増減があった時にもデータを抜き出すようにするにはどうすればいいですか? 例えば以下の通り time result 1   1 2   1 3   1 4   1 5   1 6   1 7   1 8   1 9   1 10   1 11  100 12  500 13  1000 14  1000 15  1000 16  1000 17  1000 18  1000 19  1000 20  1000 21  1000 ・  ・ ・  ・ ・  ・  ↓ time result 1   1 10  1 11  100 12  500 13  1000 20  1000 ・  ・ ・  ・ ・  ・ ここからプログラム(10行ごとに抜き出す) ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ Sub nukitori() Dim X As Worksheet Dim i As Long Dim ii As Long Dim col As Integer Dim Nukitori_Step As Long Nukitori_Step = 10 i = 2 ii = 2 '●●●見出し行が1行目なので2で始める Set X = ActiveSheet '●シートShordataがあったら削除 On Error Resume Next Application.DisplayAlerts = False Worksheets("shortdata").Delete Application.DisplayAlerts = True On Error GoTo 0 Worksheets.Add.Name = "shortdata" '●先ず、見出しをコピー Worksheets("shortdata").Rows(1).Value = X.Rows(1).Value While X.Cells(i, 1) <> "" And i < 65535 For col = 1 To 255 Worksheets("shortdata").Cells(ii, col).Value = X.Cells(i, col).Value Next If i = 2 Then i = 1 i = i + Nukitori_Step ii = ii + 1 Wend End Sub ここからプログラム(10行ごとに抜き出す+増減があった場合も抜き出す) ただし以下の箇所でエラーが起こる If i > 3 And Abs(Cells(i, 1) - Cells(i - 1)) >= 10 Then 中断モードでコードを実行することができませんと。 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ Sub 抽出() Dim i As Long Dim j As Long Dim ws1 As Worksheet Dim ws2 As Worksheet Dim Lastline As Long Dim SelFlg As Boolean '抽出データかどうかの Set ws1 = Worksheets("OriginDT") '元データ Set ws2 = Worksheets("SelectDT") '抽出データ Lastline = ws1.Cells(Rows.Count, 1).End(xlUp).Row '最終行番号を取得 ws2.Cells(1, 1) = ws1.Cells(1, 1) '見出し部分のコピー ws2.Cells(1, 2) = ws1.Cells(1, 2) j = 1 For i = 2 To Lastline SelFlg = False '10で割ったあまりが1(つまり10行おき)または最初のデータのとき If i Mod 10 = 1 Or i = 2 Then ' SelFlg = True '抽出対象にする End If '2行目以降で一つ上の行との差が10以上のとき If i > 3 And Abs(Cells(i, 1) - Cells(i - 1)) >= 10 Then SelFlg = True '抽出対象にする End If If SelFlg = True Then '抽出対象だったらコピー j = j + 1 ws2.Cells(j, 1) = ws1.Cells(i, 1) ws2.Cells(j, 2) = ws1.Cells(i, 2) End If Next End Sub

  • エクセルVBAのイベントで質問です。

    ダブルクリックイベントで、G12:G31の範囲の文字列をB10:B27の範囲(最下行)に入れていくものを使っていますが、新たにH12:H31にある文字列もダブルクリックするとC10:C27の範囲(最下行)に入れていけるようにしたいと思います。 どのようにすればいいでしょうか。 ご存知の方いらっしゃればお教えいただけると助かります。 Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Excel.Range, _ Cancel As Boolean) Dim i As Long Dim flg As Boolean If Intersect(Target, Range("G12:G31")) Is Nothing Then Exit Sub If IsEmpty(Target.Value) Then Exit Sub With Worksheets("シートA") For i = 10 To 27 If .Range("B" & i).Value = "" Then .Range("B" & i).Value = Target.Value flg = True Exit For End If Next i If flg = False Then MsgBox .Name & " がいっぱいです。" End If End With Cancel = True End Sub

  • マクロ 修正 (初心者です)

    Option Explicit Private lastRow As Long Private Index As Integer Private Sub CommandButton1_Click() Unload Me End Sub Private Sub あいまいボタン_Click() Dim last As Long If 検索名前テキストボックス.Text = "" Then MsgBox "あいまい抽出する名前を入力してください。" Exit Sub End If last = Range("A500").End(xlUp).Row Range("A2:D" & last).AutoFilter Field:=2, Criteria1:="=*" & 検索名前テキストボックス.Text & "*" End Sub Private Sub UserForm_Activate() Dim i As Long lastRow = Worksheets("顧客情報").Cells(Rows.Count, 1).End(xlUp).Row + 1 If lastRow <= 3 Then Exit Sub End If For i = 4 To lastRow 名前リストボックス.AddItem Cells(i, 2) Next End Sub Private Sub 検索ボタン_Click() Dim searchName As String searchName = 検索名前テキストボックス.Text If searchName = "" Then MsgBox "検索する名前を入力してください。" Else Dim i As Long Dim no As Long For i = 0 To 名前リストボックス.ListCount - 1 If 名前リストボックス.List(i) = searchName Then no = i 名前リストボックス.ListIndex = no Exit For ElseIf i >= 名前リストボックス.ListCount - 1 Then MsgBox "該当なし。" Exit For End If Next Index = no + 3 Rows(Index).Select End If End Sub B列に名前を入力しています B3から検索してくれるマクロを作成しました(インターネット見ながら) 別の検索も作りたくてどこをいじればいいのかわからず書き込みました G3列(住所を検索)から下側を検索したいのですがどこをいじればいいでしょうか?

専門家に質問してみよう