Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(指定なし : 指定なし)
配列について
投稿日時: 17/10/08 16:50:27
投稿者: daipon

お世話になります。
配列について以下の手順で検討しています。
@配列aを読み込み
A配列aをfunctionプロシージャに渡して関数計算させて配列cとしてsubプロシージャに戻す
B配列cを配列Lと配列Uに分配
コードは以下のとおり書いてみましたが、Bの段階でLとCの型が一致しないとのエラーとなります。
この改善方法と、functionプロシージャの方でBの処理をしてからsubプロシージャに2つの配列を戻すことも可能かどうか、ご教示頂けないでしょうか。
 
Sub matrix()
'記号の形式を定義
Dim a(1 To 4, 1 To 4) As Double, L As Variant, U As Variant, c As Variant
Dim i As Integer, j As Integer, i3 As Integer, j3 As Integer
For i = LBound(a, 1) To UBound(a, 1) ' 配列 a の一次元の最少要素数から最大要素数まで
For j = LBound(a, 2) To UBound(a, 2) ' 配列 a の二次元の最少要素数から最大要素数まで
a(i, j) = Cells(i + 1, j + 2)
Next j
Next i
ReDim L(LBound(a, 1) To UBound(a, 1), LBound(a, 2) To UBound(a, 2)) ' 動的配列をセット
ReDim U(LBound(a, 1) To UBound(a, 1), LBound(a, 2) To UBound(a, 2)) ' 動的配列をセット
c = LU(a) 'Functionプロシージャにaを引数として渡して戻り値cを受け取る
'LU行列に分配
For i = 1 To UBound(a, 1)
 For j = 1 To UBound(a, 2)
  If i < j Then
  L(i, j) = 0
  U(i, j) = c(i, j)
  ElseIf i = j Then
  L(i, j) = c(i, j)
  U(i, j) = 1
  ElseIf i > j Then
  L(i, j) = c(i, j)
  U(i, j) = 0
  End If
 Next j
Next i
End Sub
 
Function LU(ByVal a As Variant) As Variant
Dim c As Variant, L As Variant, U As Variant
Dim i As Integer, j As Integer, k As Integer
'L,Uに分配前の成分を計算(※成分が0,1,aijのものは後で配分する)
'@c(i,j)を新たに定義し、a(i,j)を初期値として取り込む
'Ai=1の領域の行列を計算
'Bi>=j,j>1の領域の行列を計算
'Ci<j,j>1の領域の行列を計算
ReDim c(LBound(a, 1) To UBound(a, 1), LBound(a, 2) To UBound(a, 2))
For i = 1 To UBound(a, 1)
 For j = 1 To UBound(a, 2)
 c(i, j) = a(i, j) '@
 If i = 1 Then 'A
 c(i, j) = c(i, j) / c(i, i)
 ElseIf j > 1 And i >= j Then 'B
  For k = 1 To j - 1
  c(i, j) = c(i, j) - c(i, k) * c(k, j)
  Next k
 ElseIf j > 1 And i < j Then 'C
  For k = 1 To i - 1
  c(i, j) = c(i, j) - c(i, k) * c(k, j)
  c(i, j) = c(i, j) / c(i, i)
  Next k
 End If
 Next j
Next i
End Function

回答
投稿日時: 17/10/08 17:18:20
投稿者: simple

Function LUが何も返していないからです。
関数名と同じ変数名を使って返してください。

回答
投稿日時: 17/10/08 19:17:59
投稿者: simple

後半に答えていなかった。
こんなふうに、ByRef(省略時はByRefとみなされる)で値を取得することもできます。
なお、できるだけ型を指定したほうがよいと思います。
 

Sub matrix()
    Dim a(1 To 4, 1 To 4) As Double
    Dim L()  As Double, U() As Double
    Dim i As Long, j As Long, i3 As Long, j3 As Long
    
    For i = LBound(a, 1) To UBound(a, 1)
        For j = LBound(a, 2) To UBound(a, 2)
            a(i, j) = Cells(i + 1, j + 2).Value
        Next j
    Next i
    
    ReDim L(LBound(a, 1) To UBound(a, 1), LBound(a, 2) To UBound(a, 2)) As Double
    ReDim U(LBound(a, 1) To UBound(a, 1), LBound(a, 2) To UBound(a, 2)) As Double
    
    Call LU(a, L, U)  'LU分解
    
    Stop
    'L,Uを使える
    
End Sub

Function LU(a() As Double, L() As Double, U() As Double)
    Dim c() As Double
    Dim i As Long, j As Long, k As Long
    
    'L,Uに分配前の成分を計算(※成分が0,1,aijのものは後で配分する)
    '@c(i,j)を新たに定義し、a(i,j)を初期値として取り込む
    'Ai=1の領域の行列を計算
    'Bi>=j,j>1の領域の行列を計算
    'Ci<j,j>1の領域の行列を計算
    ReDim c(LBound(a, 1) To UBound(a, 1), LBound(a, 2) To UBound(a, 2)) As Double
    
    For i = 1 To UBound(a, 1)
        For j = 1 To UBound(a, 2)
            c(i, j) = a(i, j)               '@
            If i = 1 Then                   'A
                c(i, j) = c(i, j) / c(i, i)
            ElseIf j > 1 And i >= j Then    'B
                For k = 1 To j - 1
                    c(i, j) = c(i, j) - c(i, k) * c(k, j)
                Next k
            ElseIf j > 1 And i < j Then     'C
                For k = 1 To i - 1
                    c(i, j) = c(i, j) - c(i, k) * c(k, j)
                    c(i, j) = c(i, j) / c(i, i)
                Next k
            End If
        Next j
    Next i
    'LU行列に分解
    For i = 1 To UBound(a, 1)
        For j = 1 To UBound(a, 2)
            If i < j Then
                L(i, j) = 0
                U(i, j) = c(i, j)
            ElseIf i = j Then
                L(i, j) = c(i, j)
                U(i, j) = 1
            ElseIf i > j Then
                L(i, j) = c(i, j)
                U(i, j) = 0
            End If
        Next j
    Next i
End Function

なお、LU分解のロジック自体は見ていません。

投稿日時: 17/10/08 19:52:43
投稿者: daipon

解答ありがとうございます。
ちなみにi,jをintegerでなくLongにする方がよいでしょうか?

回答
投稿日時: 17/10/08 20:04:52
投稿者: simple

はい、そのとおりLongを使うことをお薦めします。
例えば下記を参照してください。
「Integer型とLong型はどちらを使うべき?」
https://www.banana-juice.com/VBA/Performance/Statement/IntLong.html
 
そのことよりも、まずインデントをしっかり付けることをお薦めします。

投稿日時: 17/10/08 20:09:17
投稿者: daipon

ありがとうございました。
よくわかりました。