Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


13034 / 13646 ツリー ←次へ | 前へ→

【7301】関数を引数として用いるには? 森イチロー 03/9/2(火) 0:38 質問
【7304】Re:関数を引数として用いるには? こうしろう 03/9/2(火) 9:51 回答
【7326】Re:関数を引数として用いるには? 森イチロー 03/9/2(火) 16:35 発言
【7331】Re:関数を引数として用いるには? こうしろう 03/9/2(火) 16:54 発言
【7344】Re:関数を引数として用いるには? 森イチロー 03/9/2(火) 21:36 お礼
【7352】Re:関数を引数として用いるには? 森イチロー 03/9/3(水) 1:30 回答

【7301】関数を引数として用いるには?
質問  森イチロー  - 03/9/2(火) 0:38 -

引用なし
パスワード
   はじめまして。

C言語では関数のポインタを用いて、別の関数に関数を引数として
渡すことが可能ですよね。例えば積分の場合、被積分関数の部分の
ソースと、積分そのもの(例えば台形公式)のソースを別に書くこ
とで、任意の関数を同じ積分のソースを流用して積分することが可
能になると思います。

これをVB(VBA)でやるにはどうすればいいんでしょうか。

宜しくご教授くださいますようお願いします。

【7304】Re:関数を引数として用いるには?
回答  こうしろう  - 03/9/2(火) 9:51 -

引用なし
パスワード
   こんにちわ。

関数の名前を渡して、Application.Runを使って呼び出す
というのはどうでしょうか。

Sub test()

Debug.Print integ("y_a")
Debug.Print integ("y_b")

End Sub

Function y_a(ByVal x As Double) As Double
 y_a = (x - 3) ^ 2
End Function

Function y_b(ByVal x As Double) As Double
 y_b = (x - 5) ^ 2
End Function

Function integ(FuncName As String)
Dim i As Integer
Dim S As Double
S = 0
 For i = 1 To 10
  S = S + Application.Run(FuncName, CDbl(i)) * 1
 Next
integ = S
End Function

【7326】Re:関数を引数として用いるには?
発言  森イチロー  - 03/9/2(火) 16:35 -

引用なし
パスワード
    こうしろうさん、早速の回答ありがとうございます。

>関数の名前を渡して、Application.Runを使って呼び出す
>というのはどうでしょうか。

 ありがとうございました。いただいたソースを自分なりに改良して、
とりあえず正しく動くものは書けました。

 後学のためにもいくつか質問させてもらいたいのですが、

1.Application.Run(FuncName, CDBl(i))のCDBl(i)はどうも
 FuncNameの引数のようですが、FuncNameが引数を二つ持っている
 ケースでもこの方法は使えるのでしょうか。

2.例えばいただいたソースはVBA上では動きますが、Functionでは
 あってもExcelのワークシート上では使えない関数のようです。
  恐らくApplication.RunがVBA上のみで有効だからなのだと思う
 のですが、そういう理解で正しいのでしょうか。

>>>
 Cだとポインタの記述のときに、引数となる関数が必要とする引数
の数も同じでなければいけませんが、Application.Runの引数はどう
も沢山あってもよさそうなので、もしかすると複数の引数でもOKなの
ではないかと漠然と思ってます。

【7331】Re:関数を引数として用いるには?
発言  こうしろう  - 03/9/2(火) 16:54 -

引用なし
パスワード
   こんにちわ。

>1.Application.Run(FuncName, CDBl(i))のCDBl(i)はどうも
> FuncNameの引数のようですが、FuncNameが引数を二つ持っている
> ケースでもこの方法は使えるのでしょうか。
できます。
ご自分でやってみてください。

>2.例えばいただいたソースはVBA上では動きますが、Functionでは
> あってもExcelのワークシート上では使えない関数のようです。
>  恐らくApplication.RunがVBA上のみで有効だからなのだと思う
> のですが、そういう理解で正しいのでしょうか。
私のところでは、
セルに
=integ("y_a")と入れたらちゃんと計算されますが、
何が違うのでしょうね?
> あってもExcelのワークシート上では使えない関数のようです。
と考えたのは、どのような理由でしょうか?

> Cだとポインタの記述のときに、引数となる関数が必要とする引数
>の数も同じでなければいけませんが、Application.Runの引数はどう
>も沢山あってもよさそうなので、もしかすると複数の引数でもOKなの
>ではないかと漠然と思ってます。
試してみたら簡単に分かりますから、まずはやってみることをおすすめします。

【7344】Re:関数を引数として用いるには?
お礼  森イチロー  - 03/9/2(火) 21:36 -

引用なし
パスワード
    こうしろうさん、こんにちは。

>>1.Application.Run(FuncName, CDBl(i))のCDBl(i)はどうも
>> FuncNameの引数のようですが、FuncNameが引数を二つ持っている
>> ケースでもこの方法は使えるのでしょうか。
>できます。
>ご自分でやってみてください。

 はい、できました。Application.Runはコマンド名と
その後ろに引数をつなげればいいみたいですね。


>>2.例えばいただいたソースはVBA上では動きますが、Functionでは
>> あってもExcelのワークシート上では使えない関数のようです。
>>  恐らくApplication.RunがVBA上のみで有効だからなのだと思う
>> のですが、そういう理解で正しいのでしょうか。
>私のところでは、
>セルに
>=integ("y_a")と入れたらちゃんと計算されますが、
>何が違うのでしょうね?

 あれ? 自宅のPCだとできました。

 会社のソースに間違いがあるのか、それとも何かが
インストール不足なのか・・・。


>> Cだとポインタの記述のときに、引数となる関数が必要とする引数
>>の数も同じでなければいけませんが、Application.Runの引数はどう
>>も沢山あってもよさそうなので、もしかすると複数の引数でもOKなの
>>ではないかと漠然と思ってます。
>試してみたら簡単に分かりますから、まずはやってみることをおすすめします。

 そうですね。これを使えば関数を引数にすると便利な
積分や微分等がかなり簡単になりそうです。

 どうもありがとうございました。

【7352】Re:関数を引数として用いるには?
回答  森イチロー  - 03/9/3(水) 1:30 -

引用なし
パスワード
     自己レスですが、今回覚えたものを使って、2種類のVBA用積分関数を
作ってみました。両方ともシンプソンの公式を使った比較的高精度のもの
で、片方は用いる関数の引数は一つだけに限定されていますが、もう片方
は引数を配列化することで最大10(いくつでも変更可)までの引数を使
用できます。我流なので見苦しい点はお許しください。

 使い方はtest()にありますが、MyFuncのarg(1)が自動的に積分変数にな
り、積分変数以外のパラメータを配列cに放り込む形にしてみました。

 なので、積分変数を変更したい場合は、y_bの中のarg(1)の場所を変える
だけでOKです。これで結構使いやすくなったと思うんですが。

 ちなみにtest()のIntegralはx^2の0から10までの積分なので答えは1000/3、
Integral2は数字を放り込んでみると結局x^2+3の0から10までの積分なので
答えは1000/3+30になります。

>>>
 実は元々は積分じゃなくて他の関数を作りたかったんですが、これで
何とかできそうです(^^)。こうしろうさん、どうもありがとうございました。

>>>

Function Integral(MyFunc As String, a As Double, b As Double, N As Integer)
  Dim i As Integer
  Dim result As Double, dx As Double
  
  result = Application.Run(MyFunc, a)
  dx = (b - a) / (2 * N)
  
  For i = 1 To 2 * N - 1
    If (i Mod 2) = 1 Then result = result + 4 * Application.Run(MyFunc, a + CDbl(i) * dx)
    If (i Mod 2) = 0 Then result = result + 2 * Application.Run(MyFunc, a + CDbl(i) * dx)
  Next
  result = result + Application.Run(MyFunc, b)
  Integral = result * dx / 3
End Function

Function Integral2(MyFunc As String, a As Double, b As Double, c() As Double, N As Integer)
  Dim i As Integer
  Dim arg(10) As Double
  Dim result As Double, dx As Double
  
  For i = LBound(c) To UBound(c)
    arg(i + 1) = c(i)
  Next
  
  arg(1) = a
  result = Application.Run(MyFunc, arg)
  
  dx = (b - a) / (2 * N)
  
  For i = 1 To 2 * N - 1
    arg(1) = a + CDbl(i) * dx
    If (i Mod 2) = 1 Then result = result + 4 * Application.Run(MyFunc, arg)
    If (i Mod 2) = 0 Then result = result + 2 * Application.Run(MyFunc, arg)
  Next
  
  arg(1) = b
  result = result + Application.Run(MyFunc, arg)
  Integral2 = result * dx / 3
End Function

Function y_a(ByVal x As Double) As Double
  y_a = x * x
End Function

Function y_b(arg() As Double) As Double
  y_b = (2 * arg(1) ^ 2) ^ arg(2) / arg(3) + arg(4)
End Function

Sub test()
  Dim c(4) As Double
  Dim i As Integer
  
  For i = 1 To 3
    c(i) = i
  Next
  
  Debug.Print Integral("y_a", 0, 10, 100)
  Debug.Print Integral2("y_b", 0, 10, c, 100)
End Sub

13034 / 13646 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free