[VBA] 分数の加算・減算・乗算・除算

 数値計算では「割り算(除算)によって精度が落ちる」という問題が常につきまといます。たとえば 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

 分数型変数を使うと、有限項の数列の和などを分数の形で得るなど色々なところで応用できます。

コメント

タイトルとURLをコピーしました