0
0

Excel VBAでDKA法(Durand-Kerner-Aberth法)

Last updated at Posted at 2024-09-16

$ n $次多項式

f(z) = c_0 z^n + c_1 z^{n-1} + \cdots + c_{n-1} z + c_n

の係数$ c_0, c_1, \dots, c_n$を引数として与えた場合に、その$ n $個の根――すなわち

f(z) = c_0 \prod_{k=1}^n (z-\alpha_k) = 0

を満たす$ \alpha_0, \alpha_1, \dots, \alpha_n$を得るVBAプログラムを次のとおり自作した。

Classモジュール

複素数を表すClassモジュール

complex.cls
Option Explicit

Private Const strClassName As String = "Complex"

'============================
'プロパティ
'============================
Public re As Double '実部
Public im As Double '虚部

'=============================
'コンストラクタ(初期化処理)
'=============================
Private Sub Class_Initialize()
  re = 0
  im = 0
End Sub

'=============================
'複素数の定義(実部と虚部) z=a+bi = z.SetC(a, b)
'=============================
Public Function SetC(a As Double, b As Double)
  re = a
  im = b
End Function

'=============================
' 複素数の定義(絶対値と偏角) z=re^{iΘ} = z.SetC_RT(r, Θ)
'=============================
Public Function SetC_RT(r As Double, theta As Double)
  re = r * Cos(theta)
  im = r * Sin(theta)
End Function

'=============================
'絶対値 |z| = sqrt(a^2+b^2) = z.AbsC
'=============================
Public Function AbsC() As Double
  AbsC = Sqr(re ^ 2 + im ^ 2)
End Function

'=============================
'絶対値の二乗 |z|^2 = a^2+b^2 = z.AbsCSq
'=============================
Public Function AbsCSq() As Double
  AbsCSq = re ^ 2 + im ^ 2
End Function
 
'=============================
' 偏角 ∠z = arctan(b/a) = z.Angle
'=============================
Public Function Angle() As Double
  If re ^ 2 + im ^ 2 = 0 Then
    Angle = 0
  Else
    Angle = WorksheetFunction.Atan2(re, im)
  End If
End Function

'=============================
' 足し算 z_1+z_2 = z_1.Plus(z_2)
'=============================
Public Function Plus(ByVal z_2 As Variant) As Variant
  If (2 <= VarType(z_2) And VarType(z_2) <= 6) Then
    Set Plus = New Complex
    Plus.re = re + z_2
    Plus.im = im
  ElseIf (VarType(z_2) = 9 And TypeName(z_2) = strClassName) Then
    Set Plus = New Complex
    Plus.re = re + z_2.re
    Plus.im = im + z_2.im
  Else
    Plus = CVErr(xlErrNum)
  End If
End Function

'=============================
' 引き算 z_1-z_2 = z_1.Minus(z_2)
'=============================
Public Function Minus(ByVal z_2 As Variant) As Variant
  If (2 <= VarType(z_2) And VarType(z_2) <= 6) Then
    Set Minus = New Complex
    Minus.re = re - z_2
    Minus.im = im
  ElseIf (VarType(z_2) = 9 And TypeName(z_2) = strClassName) Then
    Set Minus = New Complex
    Minus.re = re - z_2.re
    Minus.im = im - z_2.im
  Else
    Minus = CVErr(xlErrNum)
  End If
End Function

'=============================
' 掛け算 z_1×z_2 = z_1.Times(z_2)
'=============================
Public Function Times(ByVal b As Variant) As Variant
  If (2 <= VarType(z_2) And VarType(z_2) <= 6) Then
    Set Times = New Complex
    Times.re = re * z_2
    Times.im = im * z_2
  ElseIf (VarType(z_2) = 9 And TypeName(z_2) = strClassName) Then
    Set Times = New Complex
    Times.re = re * z_2.re - im * z_2.im
    Times.im = re * z_2.im + im * z_2.re
  Else
    Times = CVErr(xlErrNum)
  End If
End Function

'============================
' 割り算 z_1 / z_2 = z_1.Div(z_2)
'============================
Public Function Div(ByVal z_2 As Variant) As Variant
  If (2 <= VarType(z_2) And VarType(b) <= 6) Then
    If z_2 = 0 Then
      Div = CVErr(xlErrNum)
    Else
      Set Div = New Complex
      Div.re = re / z_2
      Div.im = im / z_2
    End If
  ElseIf (VarType(z_2) = 9 And TypeName(z_2) = strClassName) Then
    If z_2.AbsC() = 0 Then
      Div = CVErr(xlErrNum)
    Else
      Set Div = New Complex
      Div.re = (re * z_2.re + im * z_2.im) / (z_2.AbsC() ^ 2)
      Div.im = (-re * z_2.im + im * z_2.re) / (z_2.AbsC() ^ 2)
    End If
  Else
    Div = CVErr(xlErrNum)
  End If
End Function

'============================
'共役複素数 z = a+bi → z.CompCnj = a-bi
'============================
Public Function CompCnj() As Complex
  Set CompCnj = New Complex
  CompCnj.re = re
  CompCnj.im = (-1) * im
End Function

'============================
'文字列(直交座標) z = a + bi → z.CompStr = "a+bi"
'============================
Public Function CompStr() As String
  If re = 0 Then
    If im = 0 Then
      CompStr = "0"
    ElseIf im > 0 Then
      If im = 1 Then
        CompStr = "+i"
      Else
        CompStr = Str(im) & "i"
      End If
    Else
      If im = -1 Then
        CompStr = "-i"
      Else
        CompStr = "-" & Str(Abs(im)) & "i"
      End If
    End If
  ElseIf re > 0 Then
    If im = 0 Then
      CompStr = Str(re)
    ElseIf im > 0 Then
      If im = 1 Then
        CompStr = Str(re) & "+i"
      Else
        CompStr = Str(re) & "+" & Str(im) & "i"
      End If
    Else
      If im = -1 Then
        CompStr = Str(re) & "-i"
      Else
        CompStr = Str(re) & Str(im) & "i"
      End If
    End If
  Else
    If im = 0 Then
      CompStr = "-" & Str(Abs(re))
    ElseIf im > 0 Then
      If im = 1 Then
        CompStr = "-" & Str(Abs(re)) & "+i"
      Else
        CompStr = "-" & Str(Abs(re)) & "+" & Str(im) & "i"
      End If
    Else
      If im = -1 Then
        CompStr = "-" & Str(Abs(re)) & "-i"
      Else
        CompStr = "-" & Str(Abs(re)) & "-" & Str(Abs(im)) & "i"
      End If
    End If
  End If
  CompStr = Replace(CompStr, " ", "")
End Function

'============================
' 文字列(直交座標,極座標cossin,極座標rExpΘ) z = r Exp(Θi) → z.CompStr = "r Exp(Θi)"
'============================
Public Function CompStrPolar() As String
  Dim dblAbs As Double
  Dim dblAngle As Double
  dblAbs = Sqr(re ^ 2 + im ^ 2)
  If re ^ 2 + im ^ 2 = 0 Then
    dblAngle = 0
  Else
    dblAngle = WorksheetFunction.Atan2(re, im)
  End If
  
  If dblAbs = 1 Then
    CompStrPolar = "Exp(" & Str(dblAngle) & "i)"
  Else
    CompStrPolar = Str(dblAbs) & " Exp(" & Str(dblAngle) & "i)"
  End If
End Function


標準モジュール

各種計算用の函数を定義する標準モジュール

ComplexFunc.bas
Option Explicit

Private Const strTypeComplex As String = "Complex"
Private Const dblEpsilon As Double = 10 ^ (-12) 'ニュートン法の収束基準
Private Const PI As Double = 3.14159265358979 '円周率

'=============================
'Sum函数
'=============================
Public Function SumComp(ParamArray varArray()) As Variant
  Dim cnt As Long
  Dim cmpSum As Complex: Set cmpSum = New Complex
  
  For cnt = LBound(varArray) To UBound(varArray)
    If (2 <= VarType(varArray(cnt)) And VarType(varArray(cnt)) <= 6) Then
      cmpSum.re = cmpSum.re + varArray(cnt)
      cmpSum.im = cmpSum.im + 0
    ElseIf (VarType(varArray(cnt)) = 9 And TypeName(varArray(cnt)) = strTypeComplex) Then
      cmpSum.re = cmpSum.re + varArray(cnt).re
      cmpSum.im = cmpSum.im + varArray(cnt).im
    Else
      SumComp = CVErr(xlErrNum)
      Exit Function
    End If
  Next cnt

  Set SumComp = cmpSum
End Function

'=============================
'Product函数
'=============================
Public Function ProductComp(ParamArray varArray()) As Variant
  Dim cnt As Long
  Dim dblTmp As Double
  Dim cmpProduct As Complex: Set cmpProduct = New Complex
  
  For cnt = LBound(varArray) To UBound(varArray)
    If (2 <= VarType(varArray(cnt)) And VarType(varArray(cnt)) <= 6) Then
      If cnt = LBound(varArray) Then
        cmpProduct.re = varArray(cnt)
        cmpProduct.im = 0
      Else
        dblTmp = cmpProduct.re * varArray(cnt) - cmpProduct.im * 0
        cmpProduct.im = cmpProduct.re * 0 + cmpProduct.im * varArray(cnt)
        cmpProduct.re = dblTmp
      End If
    ElseIf (VarType(varArray(cnt)) = 9 And TypeName(varArray(cnt)) = strTypeComplex) Then
      If cnt = LBound(varArray) Then
        cmpProduct.re = varArray(cnt).re
        cmpProduct.im = varArray(cnt).im
      Else
        dblTmp = cmpProduct.re * varArray(cnt).re - cmpProduct.im * varArray(cnt).im
        cmpProduct.im = cmpProduct.re * varArray(cnt).im + cmpProduct.im * varArray(cnt).re
        cmpProduct.re = dblTmp
      End If
    Else
      ProductComp = CVErr(xlErrNum)
      Exit Function
    End If
  Next cnt

  Set ProductComp = cmpProduct
End Function

'=============================
'Div函数(第1引数を被除数として、第2引数以降で順次除していく)
'=============================
Public Function DivComp(ParamArray varArray()) As Variant
  Dim cnt As Long
  Dim dblTmp As Double
  Dim cmpDiv As Complex: Set cmpDiv = New Complex
  Dim dblSq As Double
  
  For cnt = LBound(varArray) To UBound(varArray)
    If (2 <= VarType(varArray(cnt)) And VarType(varArray(cnt)) <= 6) Then
      If cnt = LBound(varArray) Then
        cmpDiv.re = varArray(cnt)
        cmpDiv.im = 0
      Else
        If varArray(cnt) = 0 Then
          DivComp = CVErr(xlErrNum)
          Exit Function
        Else
          dblTmp = cmpDiv.re / varArray(cnt)
          cmpDiv.im = cmpDiv.im / varArray(cnt)
          cmpDiv.re = dblTmp
        End If
      End If
    ElseIf (VarType(varArray(cnt)) = 9 And TypeName(varArray(cnt)) = strTypeComplex) Then
      If cnt = LBound(varArray) Then
        cmpDiv.re = varArray(cnt).re
        cmpDiv.im = varArray(cnt).im
      Else
        dblSq = varArray(cnt).re ^ 2 + varArray(cnt).im ^ 2
        If dblSq = 0 Then
          DivComp = CVErr(xlErrNum)
          Exit Function
        Else
          dblTmp = cmpDiv.re * varArray(cnt).re + cmpDiv.im * varArray(cnt).im
          cmpDiv.im = cmpDiv.im * varArray(cnt).re - cmpDiv.re * varArray(cnt).im
          cmpDiv.re = dblTmp / dblSq
          cmpDiv.im = cmpDiv.im / dblSq
        End If
      End If
    Else
      DivComp = CVErr(xlErrNum)
      Exit Function
    End If
  Next cnt

  Set DivComp = cmpDiv
End Function

'=============================
'Power函数。ただし指数は整数に限る
'=============================
Public Function PowerComp(ByVal varBase As Variant, ByVal varExp As Variant) As Variant
  Dim cnt As Long
  Dim dblTmp As Double
  Dim cmpPower As Complex: Set cmpPower = New Complex

  If (2 <= VarType(varExp) And VarType(varExp) <= 6) And (varExp = Int(varExp)) Then
    If varExp = 0 Then
      Call cmpPower.SetC(1, 0)
    Else
      Call cmpPower.SetC(1, 0)
      For cnt = 1 To Abs(varExp)
        Set cmpPower = ProductComp(cmpPower, varBase)
      Next cnt
      If varExp < 0 Then
        Set cmpPower = DivComp(1, cmpPower)
      End If
    End If
    Set PowerComp = cmpPower
  Else
    Debug.Print "error"
    Exit Function
  End If
End Function

'=============================
'絶対値
'=============================
Public Function AbsComp(varParam As Variant) As Variant
  If (2 <= VarType(varParam) And VarType(varParam) <= 6) Then
    AbsComp = Abs(varParam)
  ElseIf (VarType(varParam) = 9 And TypeName(varParam) = strTypeComplex) Then
    AbsComp = varParam.AbsC
  Else
  End If
End Function

'=============================
'多項式 f(z)=c_0 z^n + c_1 z^(n-1) + … + c_{n-2} z^2 + c_{n-1} z + c_n
'の係数c_0, c_1, ..., c_n を与えると
'その根α_1, α_2, ..., α_n を返す函数
'=============================
Public Function GetRoots(ParamArray varCoeff() As Variant) As Variant
  Dim cnt As Long, cnt2 As Long, cnt3 As Long
  Dim varTmp As Variant
  Dim compRoots01 As Variant 'ニュートン法を適用する根 α(k)_i
  Dim compRoots02 As Variant 'ニュートン法を適用する根 α(k+1)_i
  Dim compRoots11 As Variant 'f(z) = c_0(z-α_1)(z-α_2)・・・(z-α_n)
  Dim compRoots12 As Variant 'f'(z) = c_0 Π(α_i-α_j)  (i≠j)
  Dim compTemp As Complex: Set compTemp = New Complex
  Dim dblError As Double

  If UBound(varCoeff) = -1 Then
    GetRoots = CVErr(xlErrNum)
    Exit Function
  ElseIf UBound(varCoeff) = 0 Then
    If UBound(varCoeff(0)) <= 0 Then
      GetRoots = CVErr(xlErrNum)
      Exit Function
    Else
      For cnt = LBound(varCoeff(0)) To UBound(varCoeff(0))
        If Not ((2 <= VarType(varCoeff(0)(cnt)) And VarType(varCoeff(0)(cnt)) <= 6) Or (VarType(varCoeff(0)(cnt)) = 9 And TypeName(varCoeff(0)(cnt)) = strTypeComplex)) Then
          GetRoots = CVErr(xlErrNum)
          Exit Function
        End If
      Next cnt
      ReDim compRoots01(UBound(varCoeff(0)) - 1)
      ReDim varTmp(UBound(varCoeff(0)) - 1)
      For cnt = LBound(varCoeff(0)) To UBound(varCoeff(0)) - 1
        Set compRoots01(cnt) = New Complex
      Next cnt
      Select Case UBound(varCoeff(0))
        Case 1
          Set compRoots01(0) = ProductComp(DivComp(varCoeff(0)(1), varCoeff(0)(0)), -1)
'          Call RealAndComp2String(compRoots01, varTmp)
'          GetRoots = varTmp
          GetRoots = compRoots01
        Case Else
          'https://www.chart.co.jp/subject/sugaku/suken_tsushin/84/84-5.pdf
          compRoots01 = GetAberthInitial(varCoeff(0))
          ReDim compRoots02(UBound(varCoeff(0)) - 1) 'compRoots01は Case1でも使うので、これよりも前に再定義済み
          ReDim compRoots11(UBound(varCoeff(0)) - 1)
          ReDim compRoots12(UBound(varCoeff(0)) - 1)
          For cnt = LBound(varCoeff(0)) To UBound(varCoeff(0)) - 1
            Set compRoots02(cnt) = New Complex
            Set compRoots11(cnt) = New Complex
            Set compRoots12(cnt) = New Complex
          Next cnt
          Do
            cnt3 = cnt3 + 1
            dblError = 0
            For cnt = LBound(varCoeff(0)) To UBound(varCoeff(0)) - 1
              Call compRoots11(cnt).SetC(0, 0)
              For cnt2 = LBound(varCoeff(0)) To UBound(varCoeff(0))
                Set compRoots11(cnt) = SumComp(compRoots11(cnt), ProductComp(varCoeff(0)(cnt2), PowerComp(compRoots01(cnt), UBound(varCoeff(0)) - cnt2)))
              Next cnt2
            Next cnt
            For cnt = LBound(varCoeff(0)) To UBound(varCoeff(0)) - 1
              If (2 <= VarType(varCoeff(0)(0)) And VarType(varCoeff(0)(0)) <= 6) Then
                Call compTemp.SetC(Val(varCoeff(0)(0)), 0)
                Set compRoots12(cnt) = compTemp
              ElseIf (VarType(varCoeff(0)(0)) = 9 And TypeName(varCoeff(0)(0)) = strTypeComplex) Then
                Set compRoots12(cnt) = varCoeff(0)(0)
              Else
                Debug.Print "error"
                Exit Function
              End If
                
              For cnt2 = LBound(varCoeff(0)) To UBound(varCoeff(0)) - 1
                If cnt2 <> cnt Then Set compRoots12(cnt) = ProductComp(compRoots12(cnt), SumComp(compRoots01(cnt), ProductComp(-1, compRoots01(cnt2))))
              Next cnt2
              Set compRoots02(cnt) = SumComp(compRoots01(cnt), ProductComp(-1, DivComp(compRoots11(cnt), compRoots12(cnt))))
            Next cnt
            For cnt = LBound(varCoeff(0)) To UBound(varCoeff(0)) - 1
              Set compTemp = compRoots01(cnt).Minus(compRoots02(cnt))
              dblError = dblError + compTemp.AbsC
              Set compRoots01(cnt) = compRoots02(cnt)
            Next cnt
            If cnt3 Mod 1000 = 0 Then
              Stop
            End If
          Loop While dblError > dblEpsilon
          GetRoots = compRoots01
      End Select
    End If
  Else
    For cnt = LBound(varCoeff) To UBound(varCoeff)
      If Not ((2 <= VarType(varCoeff(cnt)) And VarType(varCoeff(cnt)) <= 6) Or (VarType(varCoeff(cnt)) = 9 And TypeName(varCoeff(cnt)) = strTypeComplex)) Then
        GetRoots = CVErr(xlErrNum)
        Exit Function
      End If
    Next cnt
    ReDim compRoots01(UBound(varCoeff) - 1)
    ReDim varTmp(UBound(varCoeff) - 1)
    For cnt = LBound(varCoeff) To UBound(varCoeff) - 1
      Set compRoots01(cnt) = New Complex
    Next cnt
    Select Case UBound(varCoeff)
      Case 1
        Set compRoots01(0) = ProductComp(DivComp(varCoeff(1), varCoeff(0)), -1)
        GetRoots = compRoots01
      Case Else
        compRoots01 = GetAberthInitial(varCoeff)
        ReDim compRoots02(UBound(varCoeff) - 1) 'compRoots01は Case1でも使うので、これよりも前に再定義済み
        ReDim compRoots11(UBound(varCoeff) - 1)
        ReDim compRoots12(UBound(varCoeff) - 1)
        For cnt = LBound(varCoeff) To UBound(varCoeff) - 1
          Set compRoots02(cnt) = New Complex
          Set compRoots11(cnt) = New Complex
          Set compRoots12(cnt) = New Complex
        Next cnt
        Do
          cnt3 = cnt3 + 1
          dblError = 0
          For cnt = LBound(varCoeff) To UBound(varCoeff) - 1
            Call compRoots11(cnt).SetC(0, 0)
            For cnt2 = LBound(varCoeff) To UBound(varCoeff)
              Set compRoots11(cnt) = SumComp(compRoots11(cnt), ProductComp(varCoeff(cnt2), PowerComp(compRoots01(cnt), UBound(varCoeff) - cnt2)))
            Next cnt2
          Next cnt
          For cnt = LBound(varCoeff) To UBound(varCoeff) - 1
            If (2 <= VarType(varCoeff(0)) And VarType(varCoeff(0)) <= 6) Then
              Call compTemp.SetC(Val(varCoeff(0)), 0)
              Set compRoots12(cnt) = compTemp
            ElseIf (VarType(varCoeff(0)) = 9 And TypeName(varCoeff(0)) = strTypeComplex) Then
              Set compRoots12(cnt) = varCoeff(0)
            Else
              Debug.Print "error"
              Exit Function
            End If
              
            For cnt2 = LBound(varCoeff) To UBound(varCoeff) - 1
              If cnt2 <> cnt Then Set compRoots12(cnt) = ProductComp(compRoots12(cnt), SumComp(compRoots01(cnt), ProductComp(-1, compRoots01(cnt2))))
            Next cnt2
            Set compRoots02(cnt) = SumComp(compRoots01(cnt), ProductComp(-1, DivComp(compRoots11(cnt), compRoots12(cnt))))
          Next cnt
          For cnt = LBound(varCoeff) To UBound(varCoeff) - 1
            Set compTemp = compRoots01(cnt).Minus(compRoots02(cnt))
            dblError = dblError + compTemp.AbsC
            Set compRoots01(cnt) = compRoots02(cnt)
          Next cnt
          If cnt3 Mod 1000 = 0 Then
            Stop
          End If
        Loop While dblError > dblEpsilon
        GetRoots = compRoots01
    End Select
  End If
End Function

'=============================
' Aberthの初期値の半径
' http://nalab.mind.meiji.ac.jp/~mk/lecture/ouyoukaiseki4/notebook/nonlinear-algebra/node40.html
'=============================
Private Function GetAberthRadius(ByVal varCoeff As Variant) As Variant
  Dim cnt As Long
  Dim varTmp As Variant
  Dim dblTmp As Double
  ReDim varTmp(UBound(varCoeff))
  For cnt = LBound(varCoeff) To UBound(varCoeff)
    Set varTmp(cnt) = DivComp(varCoeff(cnt), varCoeff(LBound(varCoeff)))
    If dblTmp < varTmp(cnt).AbsC Then dblTmp = varTmp(cnt).AbsC
  Next cnt
  GetAberthRadius = varTmp(1).AbsC / (UBound(varCoeff) - 1) + 1 + dblTmp
End Function

'=============================
' Aberthの初期値
' http://nalab.mind.meiji.ac.jp/~mk/lecture/ouyoukaiseki4/notebook/nonlinear-algebra/node40.html
'=============================
Private Function GetAberthInitial(ByVal varCoeff As Variant) As Variant
  Dim cnt As Long
  Dim varTmp As Variant
  Dim compTmp As Complex: Set compTmp = New Complex
  Dim dblRadius As Double
  dblRadius = GetAberthRadius(varCoeff)
  ReDim varTmp(UBound(varCoeff) - 1)
  For cnt = LBound(varCoeff) To UBound(varCoeff) - 1
    Call compTmp.SetC_RT(dblRadius, (2 * cnt + 0.5) * PI / UBound(varCoeff))
    Set compTmp = SumComp(compTmp, DivComp(ProductComp(-1, varCoeff(1)), ProductComp(varCoeff(0), UBound(varCoeff))))
    Set varTmp(cnt) = compTmp
    Set compTmp = New Complex
  Next cnt
  GetAberthInitial = varTmp
End Function

'=============================
' 複素数Classの配列を、実数のものだけ実数型に置き換える
'=============================
Private Sub IfRealThenComp2Real(ByRef varBf, ByRef varAf)
  If Not (LBound(varBf) = LBound(varAf) And UBound(varBf) = UBound(varAf)) Then
    Exit Sub
  End If
  Dim cnt As Long
  For cnt = LBound(varBf) To UBound(varBf)
    If (2 <= VarType(varBf(cnt)) And VarType(varBf(cnt)) <= 6) Then
      varAf(cnt) = varBf(cnt)
    ElseIf (VarType(varBf(cnt)) = 9 And TypeName(varBf(cnt)) = strTypeComplex) Then
      If varBf(cnt).im = 0 Then
        varAf(cnt) = varBf(cnt).re
      Else
        Set varAf(cnt) = varBf(cnt)
      End If
    Else
      Debug.Print "error"
      Exit Sub
    End If
  Next cnt
End Sub

'=============================
'複素数Classの配列を、文字列に置き換える
'=============================
Private Sub RealAndComp2String(ByRef varBf, ByRef varAf)
  If Not (LBound(varBf) = LBound(varAf) And UBound(varBf) = UBound(varAf)) Then
    Exit Sub
  End If
  Dim cnt As Long
  For cnt = LBound(varBf) To UBound(varBf)
    If (2 <= VarType(varBf(cnt)) And VarType(varBf(cnt)) <= 6) Then
      varAf(cnt) = Str(varBf(cnt))
    ElseIf (VarType(varBf(cnt)) = 9 And TypeName(varBf(cnt)) = strTypeComplex) Then
      If varBf(cnt).im = 0 Then
        varAf(cnt) = Str(varBf(cnt).re)
      Else
        varAf(cnt) = varBf(cnt).CompStr
      End If
    Else
      Debug.Print "error"
      Exit Sub
    End If
  Next cnt
End Sub

'=============================
'WorkSheet函数用
'=============================
Public Function WSFuncGetRoots(rngCoeff As Range) As Variant
  Dim strCoeff() As String
  Dim CompCoeff() As Complex
  Dim cnt As Long
  Dim varRoots As Variant

  If rngCoeff.Rows.Count > 1 And rngCoeff.Columns.Count > 1 Then
    WSFuncGetRoots = CVErr(xlErrNum)
  ElseIf rngCoeff.Rows.Count = 1 Then
    ReDim strCoeff(rngCoeff.Columns.Count - 1)
    For cnt = 0 To rngCoeff.Columns.Count - 1
      strCoeff(cnt) = rngCoeff(1, cnt + 1)
    Next cnt
  ElseIf rngCoeff.Columns.Count = 1 Then
    ReDim strCoeff(rngCoeff.Rows.Count - 1)
    For cnt = 0 To rngCoeff.Rows.Count - 1
      strCoeff(cnt) = rngCoeff(cnt + 1, 1)
    Next cnt
  End If

  ReDim CompCoeff(UBound(strCoeff))
  For cnt = LBound(CompCoeff) To UBound(CompCoeff)
    Set CompCoeff(cnt) = New Complex
    Call CompCoeff(cnt).SetC_str(strCoeff(cnt))
  Next cnt

  Dim rt As Variant
  rt = GetRoots(CompCoeff)
  ReDim varRoots(1 To UBound(rt) + 1)

  For cnt = LBound(rt) To UBound(rt)
    varRoots(cnt + 1) = rt(cnt).CompStr
  Next cnt

  WSFuncGetRoots = varRoots

End Function

計算例・使い方

Module1.bas
Option Explicit

Public Sub test001()
  Dim cnt As Long
  Dim a1 As Complex:  Set a1 = New Complex
  Dim a2 As Complex:  Set a2 = New Complex
  Dim a3 As Complex:  Set a3 = New Complex

  Dim rt As Variant

  Set rt = Nothing
  rt = GetRoots(1, 0, 1)
  For cnt = LBound(rt) To UBound(rt)
    Debug.Print rt(cnt).CompStr
  Next cnt
  '+i
  '-i

  Call a1.SetC(3, 2)
  Call a2.SetC(5, 0)
  Call a3.SetC(2, 1)
  Set rt = Nothing
  rt = GetRoots(a1, a2, a3)
  For cnt = LBound(rt) To UBound(rt)
    Debug.Print rt(cnt).CompStr
  Next cnt
  '-.836846641040605+1.09033036388437i
  '-.316999512805549-.3210995946536i

  Call a1.SetC(0, -8)
  Set rt = Nothing
  rt = GetRoots(1, 0, 0, a1)
  For cnt = LBound(rt) To UBound(rt)
    Debug.Print rt(cnt).CompStr
  Next cnt
  '1.73205080756888+i
  '-1.73205080756888+i
  '-2i

  Set rt = Nothing
  rt = GetRoots(33, 140, 266, 140, 33)
  For cnt = LBound(rt) To UBound(rt)
    Debug.Print rt(cnt).CompStr
  Next cnt
  '-.323693680587964+.274409342564836i
  '-1.79751844062416+1.5238352897217i
  '-1.79751844062416-1.5238352897217i
  '-.323693680587964-.274409342564836i

End Sub
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0