Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


10152 / 13646 ツリー ←次へ | 前へ→

【23300】VBAで nekokai 05/3/18(金) 15:06 質問[未読]
【23353】Re:VBAで G-Luck 05/3/19(土) 9:28 発言[未読]
【23363】Re:VBAで nekokai 05/3/19(土) 17:52 質問[未読]
【23366】Re:VBAで G-Luck 05/3/19(土) 19:09 発言[未読]
【23367】Re:VBAで G-Luck 05/3/19(土) 19:24 回答[未読]
【23377】Re:VBAで G-Luck 05/3/20(日) 10:52 発言[未読]
【23380】Re:VBAで ichinose 05/3/20(日) 11:00 発言[未読]
【23412】Re:VBAで nekokai 05/3/22(火) 11:30 お礼[未読]
【23423】Re:VBAで ichinose 05/3/22(火) 19:06 発言[未読]
【23433】Re:VBAで nekokai 05/3/23(水) 9:59 お礼[未読]

【23300】VBAで
質問  nekokai  - 05/3/18(金) 15:06 -

引用なし
パスワード
   エクセルのVBAで下記の作業をするにはどうしたらよいのでしょう?

「C」で作成したスクリプト
↓ があります。
congruence( m n a b )
(for k = 1 to m step 1 )
j=m1(nk+b-a)
break j=floor(j)
return m*j+a

エクセルのシートに下記の入力セルを設け、a b m n の値を入力すると、上記のスクリプトを作動させて その解をセル「k」の場所に表示させたいのです。
x≡a(mod m)
x≡b(mod n)
x=K

VBAの知識はほとんどありません。
よろしくお願いします。

【23353】Re:VBAで
発言  G-Luck  - 05/3/19(土) 9:28 -

引用なし
パスワード
   ▼nekokai さん:
>エクセルのVBAで下記の作業をするにはどうしたらよいのでしょう?
>
>「C」で作成したスクリプト
>↓ があります。
>congruence( m n a b )
>(for k = 1 to m step 1 )
>j=m1(nk+b-a)
>break j=floor(j)
>return m*j+a
>
>エクセルのシートに下記の入力セルを設け、a b m n の値を入力すると、上記のスクリプトを作動させて その解をセル「k」の場所に表示させたいのです。
>x≡a(mod m)
>x≡b(mod n)
>x=K
>
>VBAの知識はほとんどありません。
>よろしくお願いします。

Cについては、詳しくないのでわかりませんが、
やりたいことを言葉で表現していただければ、
VBA又はExcelの計算での対応も可能かと思います。
また、スクリプトを作動させてということですが、同じようなものをVBAで書くという方法ではいけにないのでしょうか?

【23363】Re:VBAで
質問  nekokai  - 05/3/19(土) 17:52 -

引用なし
パスワード
   G-Luckさん

返信ありがとうございます。
VBAでスクリプトを作動させる必要はなく、仰る通りエクセル関数またはエクセルVBAで同じような計算結果が得られれば、それで問題ありません。

スクリプトの意味とVBAでしたい作業のぐ具体的な内容ですが、要するにスクリプトの内容は「連立合同式の解」の計算で、その計算結果をエクセルのシート上に表示させたいということです。

x≡a(mod m)
x≡b(mod n)
x=K
↑ これが連立合同式です。

式をエクセルのシートに書き込んでおいて、「a b m n」のセルに数字を入力すると「K」のセルに「解」の計算結果が表示されれば問題ありません。
連立合同式における計算結果は基本的にすべて「整数」です。

「解」を得るための計算式がスクリプトの内容なのですが、
「a b m n」の計算を「j」としてその解を「k」に表示させる形式をとっています。
計算式が
j=m1(nk+b-a)
の部分です。
表記しづらいのですが、1/m*(n*k+b-a) が計算式となります。
これを、整数の値がでるまでループして整数値がでたらループから抜ける、という内容です。なぜループするかというと、連立合同式の一般解は、
x≡a(mod m)
x≡b(mod n)
の場合、mとnの最小公倍数+k という形になり、この「k」を解として表示させます。
よって(n*k+b-a)がmで割って「1」余る「k」が得られるまで
(例えば1〜1000までを範囲として)
ループすることになります。

あまり巧くない説明ですみません。
具体的な計算例は以下のようになります。
x≡1(mod 4)
x≡7(mod 11)
x=77+15

77が4 11の最小公倍数でK=+15となります。
これをエクセルまたはエクセルVBAで計算および表示が可能であれば、よろしくお願いします。

【23366】Re:VBAで
発言  G-Luck  - 05/3/19(土) 19:09 -

引用なし
パスワード
   ▼nekokai さん:

整理するため、記します。
誤りがあれば、ご指摘ください。

>x≡a(mod m)
>x≡b(mod n)

を満たす、xを求めよということですね。

(mod n)
は、mod n の逆演算の意味で、ようするに

x mod m = a
x mod n = b

を満たす、xを求めよ

上記式を変更すると
x = j*m + a
x = k*n + b
ただし、j,kは整数

よって
j*m + a = k*n + b
j = (k*n+b-a)/m
ただし、j,kは整数

だから、上記式を満たす最小のj及びkを求め、最小のXを導き出したい。

>あまり巧くない説明ですみません。
>具体的な計算例は以下のようになります。
>x≡1(mod 4)
>x≡7(mod 11)
>x=77+15

上に答えは、x=29では?

【23367】Re:VBAで
回答  G-Luck  - 05/3/19(土) 19:24 -

引用なし
パスワード
   VBA流に書き換えたました。
a,b,m,n,kをシート状のどこかに定義してください。
Excelのシート状の定義とは、
挿入>名前>定義
のことです。


Sub Main()
  Dim a As Long
  Dim b As Long
  Dim m As Long
  Dim n As Long
  Dim j As Double
  Dim k As Long
  
  With ThisWorkbook
    a = .Names("a").RefersToRange.Value
    b = .Names("b").RefersToRange.Value
    m = .Names("m").RefersToRange.Value
    n = .Names("n").RefersToRange.Value
  End With
  
  For k = 1 To m
    j = (n * k + b - a) / m
    If j = Int(j) Then Exit For
  Next k
  
  ThisWorkbook.Names("k").RefersToRange.Value = n * k + b

End Sub

【23377】Re:VBAで
発言  G-Luck  - 05/3/20(日) 10:52 -

引用なし
パスワード
   よく思えば、そのまま割って余りを判定すれば確実なのでは?
と思ったのでそのようなものを作ってみました。

Sub Main()
  Dim a As Long
  Dim b As Long
  Dim m As Long
  Dim n As Long
  Dim j As Long
  Dim k As Long
  
  With ThisWorkbook
    a = .Names("a").RefersToRange.Value
    b = .Names("b").RefersToRange.Value
    m = .Names("m").RefersToRange.Value
    n = .Names("n").RefersToRange.Value
  End With
  
  For k = 1 To m
    j = n * k + b
    If j Mod m = a Then Exit For
  Next k
  
  ThisWorkbook.Names("k").RefersToRange.Value = j
End Sub

【23380】Re:VBAで
発言  ichinose  - 05/3/20(日) 11:00 -

引用なし
パスワード
   ▼nekokai さん、G-Luckさん、おはようございます。
>
連立合同式の一般解は、
>x≡a(mod m)
>x≡b(mod n)
>の場合、mとnの最小公倍数+k という形になり、この「k」を解として表示させます。
>よって(n*k+b-a)がmで割って「1」余る「k」が得られるまで
私は、↑この文だけ見てアプローチしました。
つまり、0〜最小公倍数-1の数値の間で
mで割ってあまりがaかつ、nで割ってあまりがbになる値を求める方法です。

'===============================================================
Sub test()
  Dim a As Variant
  Dim b As Variant
  Dim m As Variant
  Dim n As Variant
  Dim k As Variant
  Dim gcd As Variant
  a = Array(1, 2, 3, 0)
  b = Array(7, 11, 13, 200)
  m = Array(4, 9, 13, 29)
  n = Array(11, 19, 33, 600)
' ↑4例をサンプルにしました
  For idx = LBound(a) To UBound(a)
   k = get_k(a(idx), b(idx), m(idx), n(idx), gcd)
   If VarType(k) <> vbBoolean Then
    MsgBox "x≡" & a(idx) & "(mod " & m(idx) & ")" & vbLf & _
        "x≡" & b(idx) & "(mod " & n(idx) & ")" & vbLf & _
        vbLf & "x≡" & k & "(mod " & gcd & ")"
   Else
    MsgBox "x≡" & a(idx) & "(mod " & m(idx) & ")" & vbLf & _
        "x≡" & b(idx) & "(mod " & n(idx) & ")" & vbLf & _
        vbLf & "error"
    End If
   Next idx
End Sub
'=======================================================================
Function get_k(a As Variant, b As Variant, m As Variant, n As Variant, gcd As Variant)
  gcd = m * n / get_GCD(m, n)
  '↑m,nの最小公倍数
  ans = False
  k = 0
  Do While k < gcd
   If (k Mod m) = a And (k Mod n) = b Then
    ans = True
    Exit Do
    End If
   k = k + 1
   Loop
  If ans = True Then
   get_k = k
  Else
   get_k = False
   End If
End Function
'===================================================================
Function get_GCD(n1 As Variant, n2 As Variant) As Long
  '最大公約数を求める
  Dim val1 As Long
  Dim val2 As Long
  Dim amari As Long
  val1 = n1
  val2 = n2
  get_GCD = 1
  Do While val2 <> 0
   amari = val1 Mod val2
   If amari = 0 Then
    get_GCD = val2
    End If
   val1 = val2
   val2 = amari
   Loop
End Function

試してみてください

【23412】Re:VBAで
お礼  nekokai  - 05/3/22(火) 11:30 -

引用なし
パスワード
   G-Luckさん
ichinoseさん

お二人ともありがとうございます。
合同式に関する私の説明が拙く、解りづらかった事と思います。
私はVBA初心者なので、逆にお二人のVBA記述がなかなか理解できませんが。(笑)
とりあえず試してみようと思います。

合同式のスクリプトに関する理解は、ichinoseさんのご理解の方が正しいような気がします。そこでお二人にお願いなのですが、VBAで書いたマクロのエクセルシートを直接ファイル添付で送信して頂けないでしょうか?私がこれから書くと非常に時間が、、、、(汗)。
実は、合同式の解を求める連立は2元と3元両方必要で、もう一度簡単にご説明します。

1)合同式が2つの場合。

x≡ 1 mod 7
x≡ 4 mod 11
のとき、一般解はx=77p+15 となります。
mとnの最小公倍数+kという形ですが、pは任意の整数です。

合同式の基本定理
x≡y (mod m)において x=y+pm になるという形式です。
これが、合同式2つになると
x≡ a mod m
x≡ b mod n
のとき、x=LCM(m,n)p+k
となります。
よつて、求めたい整数kは
(n*k+b-a)がmで割って「1」余る[「k」として計算されます。
なので、ichinoseさんに理解して頂いたとおり
「つまり、0〜最小公倍数-1の数値の間で
mで割ってあまりがaかつ、nで割ってあまりがbになる値を求める方法です」
で正解かと思われます。

よって
x≡ 1 mod  7
x≡ 4 mod 11
congruence(7,11,1,4)=15 と LCM(7,11)=77
で一般解は
x=77p+15

2)合同式が3つの場合 例えば

x≡ 2 mod 3
x≡ 3 mod 5
x≡ 2 mod 7
まず
x≡ 2 mod 3
x≡ 3 mod 5
の一般解congruence(3,5,2,3)=8 と LCM(3,5)=15 を求めます。
次に
x≡ 8 mod 15
x≡ 2 mod 7
としたうえで、2つの合同式の場合と同じように
x≡ 8 mod 15
x≡ 2 mod 7
congruence(7,15,2,8)=23 と LCM(15,7)=105を求めて
x=105p+23
となります。

できれば、上記2つのVBAがマクロで作動するエクセルブックを2つ、下記アドレスまでご送信頂けると助かります。
セルの場所はA1からそれぞれ
x≡a(mod m)
x≡b(mod n)
x=K

x≡a(mod M)
x≡b(mod L)
x≡c(mod N)
x=K

という形でかまいません。よろしくおねがい致します。

sattshi_2005@mail.goo.ne.jp

【23423】Re:VBAで
発言  ichinose  - 05/3/22(火) 19:06 -

引用なし
パスワード
   ▼nekokai さん
こんばんは。
プログラムのインターフェースを変えました。

最大公倍数は、LCMでしたっけ?

'=======================================================
Sub test()
  Dim a As Variant
  Dim b As Variant
  Dim m As Variant
  Dim n As Variant
  Dim k As Variant
  Dim lcm As Variant
' x≡1(mod7)
' x≡4(mod11)
' 場合
'
  a = Array(1, 4)
  m = Array(7, 11)
  ReDim mesarray(UBound(m))
  For idx = LBound(m) To UBound(m)
   mesarray(idx) = "x≡" & a(idx) & "(mod " & m(idx) & ")"
   Next idx
  mes = Join(mesarray(), vbLf)
  mes = mes & vbLf & vbLf
  k = get_godou(a, m, lcm)
  If VarType(k) <> vbBoolean Then
   MsgBox mes & "x≡" & k & "(mod " & lcm & ")"
  Else
   MsgBox mes & "error"
   End If

'
' x≡2(mod3)
' x≡3(mod5)
' x≡2(mod7)
' 場合
'
  a = Array(2, 3, 2)
  m = Array(3, 5, 7)
  ReDim mesarray(UBound(m))
  For idx = LBound(m) To UBound(m)
   mesarray(idx) = "x≡" & a(idx) & "(mod " & m(idx) & ")"
   Next idx
  mes = Join(mesarray(), vbLf)
  mes = mes & vbLf & vbLf
  k = get_godou(a, m, lcm)
  If VarType(k) <> vbBoolean Then
   MsgBox mes & "x≡" & k & "(mod " & lcm & ")"
  Else
   MsgBox mes & "error"
   End If

End Sub

'======================================
Function get_godou(a As Variant, m As Variant, lcm As Variant) As Variant
'合同式を解く?
'input a(配列)x≡a(mod m) のaに相当する数値の配列
'    m(配列) x≡a(mod m) のmに相当する数値の配列
'output lcm--配列mの最小公倍数
'    get_godou----nekokai さんおっしゃるk
'           Falseの場合、解なし    
  lcm = m(LBound(m))
  For idx = LBound(m) + 1 To UBound(m)
   lcm = lcm * m(idx) / get_GCD(lcm, m(idx))
  '↑最小公倍数
   Next idx
  k = 0
  Do While k < lcm
   ans = True
   For idx = LBound(m) To UBound(m)
    If (k Mod m(idx)) <> a(idx) Then
     ans = False
     Exit For
     End If
    Next idx
   If ans = True Then Exit Do
   k = k + 1
   Loop
  If ans = True Then
   get_godou = k
  Else
   get_godou = False
   End If
End Function

'================================
Function get_GCD(n1 As Variant, n2 As Variant) As Long
  '最大公約数を求める
  Dim val1 As Long
  Dim val2 As Long
  Dim amari As Long
  val1 = n1
  val2 = n2
  get_GCD = 1
  Do While val2 <> 0
   amari = val1 Mod val2
   If amari = 0 Then
    get_GCD = val2
    End If
   val1 = val2
   val2 = amari
   Loop
End Function

私は、この合同式というものをnekokai さんが投稿されるまで
知りませんでしたが(だって、合同って言ったら三角形の・・・だもん)、
ちなみにこれって、大学の数学科では習うものなのですか?

これで一応、解は得られています。確認して下さい。


>sattshi_2005@mail.goo.ne.jp

上記のアドレスに添付して送付しておきます。
尚、このコードは、Excel2000で確認したものです。

【23433】Re:VBAで
お礼  nekokai  - 05/3/23(水) 9:59 -

引用なし
パスワード
   ichinoseさん

ありがとうございます。
LCMは 最小公倍数です。
マクロはこれから確認してみます。

合同式は、大学の理数系の人じゃないと習わないかも知れません。
「整数論」とういう分類で、最近はセキュリティー関係に応用されていたりもします。
RSAなどの「素数」を扱うセキュリティー暗号などでは一般的です。
合同式そのものは、数学では珍しく「西洋数学」ではなく「東洋数学」のひとつで、別名「中国式余剰定理」とも呼ばれるものです。
フェルマーの定理や、ガウスの理論でも証明された「整数論」では基礎的な分野です。

エクセルの事で、またお世話になるかも知れません(汗)。
よろしくお願いします。
今回はありがとうございました。

10152 / 13646 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free