概要

 ExcelVBAにおける複素数クラスモジュールを自作し、複素数計算のコーディングができることを確認した。(2015/03/01 4.動作確認に説明を追加)


背景と目的

 私はExcelVBAをよく使用するが、電気回路やディジタル信号処理の計算を行うときに複素数を扱えると便利だろうということに気づいた。そこで、ExcelVBAで複素数の計算を出来るようにしてみる。


詳細
1.構想

 始めに思いついたのは、実部と虚部の2つの要素を持つ構造体だったが、複素数は極形式で表したりすることもあるし、四則演算やべき乗といった計算はつき物なので、これらをまとめたクラスを作成するのが、いいのではないかと考えた。そこで、今回は、複素数クラスを作成することにする。

2.設計

 複素数クラスは以下のように設計した。プロパティは、実部、虚部だけでなく絶対値と偏角を持たせた。

  • Real:実部
  • Imaginary:虚部
  • Absolute:絶対値
  • Argument:偏角

 また、メソッドは以下のとおり。よく使う演算を用意した。

  • imsum:加算
  • imsub:引き算
  • improduct:乗算
  • imdiv:除算
  • impower:べき乗
3.実装

 VBAのクラスモジュールを使用し、実装したソースコードは以下のとおり。

Option Explicit '変数の宣言を強制

'変数の宣言部----------------------------------------------------------------------------------------------------------
Private m_re As Double '実部
Private m_im As Double '虚部
Private m_abs As Double '絶対値
Private m_arg As Double '偏角[±πrad]
Private pi As Double

'プロパティの宣言部----------------------------------------------------------------------------------------------------
Public Property Get Real() As Double
    Real = m_re
End Property
Public Property Get Imaginary() As Double
    Imaginary = m_im
End Property
Public Property Get Absolute() As Double
    Absolute = m_abs
End Property
Public Property Get Argument() As Double
    Argument = m_arg
End Property

'コンストラクタ
Private Sub Class_Initialize()

    SetReIm 1, 0
    
    pi = Math.Atn(1) * 4

End Sub
'デストラクタ
Private Sub Class_Terminate()

End Sub
'初期化メソッド
Public Sub Init(Optional a_re As Double = 1, Optional a_im As Double = 0)

    SetReIm a_re, a_im

End Sub

'値をセットする(複素形式)
Public Sub SetReIm(a_re As Double, a_im As Double)

    '値の格納
    m_re = a_re
    m_im = a_im

    '絶対値の計算
    Call imabs
    
    '偏角の計算
    Call imarg
    
End Sub

'値をセットする(極形式)
Public Sub SetAbsArg(a_abs As Double, a_arg As Double)

    '値の格納
    m_abs = a_abs
    If a_arg > 0 Then
        m_arg = a_arg - Int((a_arg + pi) / (2 * pi)) * 2 * pi
    ElseIf a_arg < 0 Then
        m_arg = a_arg - Int((a_arg - pi) / (2 * pi) + 1) * 2 * pi
    Else
        m_arg = a_arg
    End If

    '絶対値の計算
    Call imreal
    
    '偏角の計算
    Call imimaginary
    
End Sub

'各種演算
'和
Public Function imsum(a_cn As ComplexNumber) As ComplexNumber

    Set imsum = New ComplexNumber

    imsum.SetReIm m_re + a_cn.Real, m_im + a_cn.Imaginary

End Function

'積
Public Function improduct(a_cn As ComplexNumber) As ComplexNumber

    Set improduct = New ComplexNumber

    improduct.SetAbsArg m_abs * a_cn.Absolute, m_arg + a_cn.Argument

End Function

'差
Public Function imsub(a_cn As ComplexNumber) As ComplexNumber

    Set imsub = New ComplexNumber

    imsub.SetReIm m_re - a_cn.Real, m_im - a_cn.Imaginary

End Function

'商
Public Function imdiv(a_cn As ComplexNumber) As ComplexNumber

    Set imdiv = New ComplexNumber

    imdiv.SetAbsArg m_abs / a_cn.Absolute, m_arg - a_cn.Argument

End Function

'べき乗
Public Function impower(a_n As Double) As ComplexNumber

    Set impower = New ComplexNumber

    impower.SetAbsArg m_abs ^ a_n, m_arg * a_n

End Function

'絶対値を計算する
Private Sub imabs()

    m_abs = Math.Sqr(m_re ^ 2 + m_im ^ 2)

End Sub

'偏角(±πで表示)を計算する
Private Sub imarg()

    '結果は0~±π/2の値を返す
    'atn関数は実部虚部の正負が判断できないから
    '±π/2~±πまでの間は実部、虚部の符号を考えて
    '場合わけする必要がある

    If m_re > 0 Then
        '実部が正のとき(0~±π/2)
        m_arg = Math.Atn(m_im / m_re)
    ElseIf m_re < 0 Then
        '実部が負のとき(±π/2~±π)
        If m_im > 0 Then
            '虚部が正のとき(+π/2<θ<+π)
            m_arg = Math.Atn(m_im / m_re) + Math.Atn(1) * 4
        Else
            '虚部が負または0のとき(-π/2>θ>=-π)
            m_arg = Math.Atn(m_im / m_re) - Math.Atn(1) * 4
        End If
    Else
        '実部が0のとき(0除算を避ける)
        If m_im > 0 Then
            '虚部が正のとき(+π/2)
            m_arg = Math.Atn(1) * 2
        ElseIf m_im < 0 Then
            '虚部が負のとき(-π/2)
            m_arg = -Math.Atn(1) * 2
        Else
            '虚部が0のとき(本当は不定形だが0とする)
            m_arg = 0
        End If
    End If

End Sub

'実部を計算する
Private Sub imreal()

    m_re = m_abs * Math.Cos(m_arg)

End Sub

'虚部を計算する
Private Sub imimaginary()

    m_im = m_abs * Math.Sin(m_arg)

End Sub

4.動作確認

 動作確認は、以下のプロシージャを作成して行った。(念のため、手順を書くと、同一プロジェクト内に、上記ComplexNumberクラスモジュールをインポートおよび標準モジュールを追加。標準モジュール内に以下のコードを書き、実行する。詳細は図1を参照)

Public Sub test_cn()

    'クラスのオブジェクトを作成
    Dim cn1 As New ComplexNumber
    Dim cn2 As New ComplexNumber
    Dim cn3 As New ComplexNumber
    
    'cn1,cn2にそれぞれ大きさ1、偏角π/4を与える
    cn1.SetAbsArg 1, Math.Atn(1) '1/√2 + j1/√2
    cn2.SetAbsArg 1, Math.Atn(1) '1/√2 + j1/√2
    
    '足し算のメソッドimsumを試す
    Set cn3 = cn1.imsum(cn2) 'cn3 = √2 + j√2となる
    
    '結果確認
    'イミディエイトウインドウに、cn3の各プロパティを出力して確かめる
    Debug.Print cn3.Real '実部(√2)
    Debug.Print cn3.Imaginary '虚部(√2)
    
    Debug.Print cn3.Absolute '絶対値(2)
    Debug.Print cn3.Argument * 180 / Math.Atn(1) / 4 '偏角(π/4)

End Sub
20150301224646
図1 動作確認した結果


まとめと今後の課題

 ExcelVBAで使用できる複素数クラスモジュールを作成し、動作確認できた。今後はこれを用いてディジタル信号処理、電気回路の計算を行いたい。