数値計算では「割り算(除算)によって精度が落ちる」という問題が常につきまといます。たとえば VBA で 1/3 のような計算をさせると「0.333333333333333」という 15 桁の数値を返します。本来であれば 1/3 の小数点以下は無限に続くわけですから、これだけでも僅かに精度を落としてしまっているのです。つまり数値計算では 1/2 + 1/3 というような簡単な計算さえも正しい答えを返さないことになってしまいます。そこで、こうした事態を防ぐために分数同士の計算は分数で返すような関数をつくることを考えてみます。
[VBA] 分数型変数と分数演算関数
そのためにはユーザー定義変数(構造体)によって分数型変数を定義する必要があります。宣言セクションに以下のステートメントを書き込んでください。
'[VBA]分数型変数の定義 Type Fraction num As Long den As Long End Type
Fraction 型変数は分子 (numerator) に相当する num と、分母 (denominator) に相当する den という2つの変数を同時に格納することになります。次に2つの引数を与えて分数を定義しましょう。分子 a と分母 b を指定して分数を定義する FRAC 関数のコードです。
'[VBA]分数の定義
Function FRAC(a As Long, b As Long) As Fraction
Dim fgcd As Long
'aとbの最大公約数を計算
fgcd = WorksheetFunction.Gcd(a, b)
'約分します
FRAC.num = a / fgcd
FRAC.den = b / fgcd
End Function
分数関数 FRAC() を呼びだすときは
FRAC(分子,分母)
のように記述します。答えは約分された形で返されます。たとえば
'[VBA]分数関数テストプロシージャ Sub FRAC_TEST() Dim x As Fraction x = FRAC(3, 6) Debug.Print x.num & "/" & x.den End Sub
を実行すると 3/6 を約分して 1/2 という値が表示されます。
分数の加算(減算)
引数に2つの分数を与えて和を返す SUM_FRAC 関数です。
'[VBA]分数加算関数の定義 Function SUM_FRAC(f1 As Fraction, f2 As Fraction) As Fraction Dim f3num As Long Dim f3den As Long Dim f3gcd As Long '分子(numerator)の計算 f3num = f1.num * f2.den + f1.den * f2.num '分母(denominator)の計算 f3den = f1.den * f2.den '分子と分母の最大公約数 f3gcd = WorksheetFunction.Gcd(f3num, f3den) '分子と分母を最大公約数で割って約分する SUM_FRAC.num = f3num / f3gcd SUM_FRAC.den = f3den / f3gcd End Function
分数加算関数 SUM_FRAC() は
SUM_FRAC(分数1,分数2)
という形で呼びだします。たとえば 1/2 + 1/3 を計算させる場合は次のようなコードを書きます。
'[VBA]分数加算関数テストプロシージャ Sub SUM_FRAC_TEST() Dim f1 As Fraction Dim f2 As Fraction Dim f3 As Fraction f1 = FRAC(1, 2) f2 = FRAC(1, 3) f3 = SUM_FRAC(f1, f2) Debug.Print f3.num & "/" & f3.den End Sub
SUM_FRAC_TEST() を実行すると 5/6 という値が返ります。引き算をさせたいときは引くほうの分数を
FRAC(-1,3)
のように記述して、SUM_FRAC() に渡します。
分数の乗算
分数同士の掛け算をする PRODUCT_FRAC 関数です。
'[VBA]分数乗算関数の定義 Function PRODUCT_FRAC(f1 As Fraction, f2 As Fraction) As Fraction Dim f3num As Long Dim f3den As Long Dim f3gcd As Long f3num = f1.num * f2.num f3den = f1.den * f2.den f3gcd = WorksheetFunction.Gcd(f3num, f3den) PRODUCT_FRAC.num = f3num / f3gcd PRODUCT_FRAC.den = f3den / f3gcd End Function
分数乗算関数 PRODUCT_FRAC() は
PRODUCT_FRAC(分数1,分数2)
という形で呼びだします。たとえば 2/7 × 3/5 を計算させる場合は次のようなコードを書きます。
'[VBA]分数乗算関数テストプロシージャ Sub PRODUCT_FRAC_TEST() Dim f1 As Fraction Dim f2 As Fraction Dim f3 As Fraction f1 = FRAC(2, 7) f2 = FRAC(3, 5) f3 = PRODUCT_FRAC(f1, f2) Debug.Print f3.num & "/" & f3.den End Sub
PRODUCT_FRAC_TEST() を実行すると 6/35 という値が返ります。
分数の除算
分数同士の割り算をする DIV_FRAC関数です。
'[VBA]分数除算関数の定義 Function DIV_FRAC(f1 As Fraction, f2 As Fraction) As Fraction Dim f3num As Long Dim f3den As Long Dim f3gcd As Long f3num = f1.num * f2.den f3den = f1.den * f2.num f3gcd = WorksheetFunction.Gcd(f3num, f3den) DIV_FRAC.num = f3num / f3gcd DIV_FRAC.den = f3den / f3gcd End Function
分数除算関数 DIV_FRAC は
DIV_FRAC(分数1,分数2)
という形で呼びだします。3/2 ÷ 4/3 を計算させるときには次のようなマクロを実行します。
'[VBA]分数除算関数テストプロシージャ Sub DIV_FRAC_TEST() Dim f1 As Fraction Dim f2 As Fraction Dim f3 As Fraction f1 = FRAC(2, 3) f2 = FRAC(3, 4) f3 = DIV_FRAC(f1, f2) Debug.Print f3.num & "/" & f3.den End Sub
分数型変数を使うと、有限項の数列の和などを分数の形で得るなど色々なところで応用できます。
エクセルや数学に関するコメントをお寄せください