新しく発言する EXIT インデックスへ
関数引数

  関数引数 クスクス 2006/12/05 19:17:54 
  FullBASICでは,関数を引数とすることができ... 白石 和夫 2006/12/05 20:25:43 
   └残念ながら素直な書き方で関数引数モドキを... クスクス 2006/12/06 15:02:57 
    └具体的な問題と例文を出されては、いかがで... SECOND 2006/12/06 18:40:33 
     └一つの解決策として、関数を引数として渡す... クスクス 2006/12/07 16:55:53 
      └!cos(t)のtin[0,x]における定積分sn(x)のグ... クスクス 2006/12/07 16:57:21 
       ├!確かにdef定義の名前が引数に置けなくて残... SECOND 2006/12/07 21:25:39 
       │└なるほど、M,Nをswapするよりコードがすっき... クスクス 2006/12/08 19:40:46 
       │ └!上書き、御免。 SECOND 2006/12/08 21:05:38 
       │  └定義による数値積分の性能が悪いことが分か... クスクス 2006/12/10 16:58:15 
       ├このように記述するのではまずいのですか? 山中和義 2006/12/07 21:58:09 
       └文字列で関数を渡す。ひょっとして、こうい... 山中和義 2006/12/08 12:46:32 
        ├つづき 山中和義 2006/12/08 12:49:08 
        └さらに、つづき 山中和義 2006/12/08 12:50:34 
         └こんなサンプルがあったんですか。manにない... クスクス 2006/12/08 20:13:24 

  関数引数 クスクス 2006/12/05 19:17:54  ツリーへ

関数引数 返事を書く
クスクス 2006/12/05 19:17:54
Cでソート関数や数値積分関数を書いたりする場合、比較関数や
被積分関数を引数として渡したりしますが、十進BASICで同様のことを簡単に行う方法はないでしょうか?

  FullBASICでは,関数を引数とすることができ... 白石 和夫 2006/12/05 20:25:43  ツリーへ

Re: 関数引数 返事を書く
白石 和夫 2006/12/05 20:25:43
Full BASICでは,関数を引数とすることができません。
十進BASICでは,裏技的な手法を用いれば,それに近いことができます。
http://hp.vector.co.jp/authors/VA008683/ExtProg.htm

   └残念ながら素直な書き方で関数引数モドキを... クスクス 2006/12/06 15:02:57  ツリーへ

Re: FullBASICでは,関数を引数とすることができ... 返事を書く
クスクス 2006/12/06 15:02:57
残念ながら素直な書き方で関数引数モドキを実現する方法はないようですね。スマートではありませんが、数値積分副プログラムの場合、被積分関数の数だけ積分ルーチンを用意するか、引数に関数番号を加えて指定番号の関数を積分するのが安全、簡単でしょう。

    └具体的な問題と例文を出されては、いかがで... SECOND 2006/12/06 18:40:33  ツリーへ

Re: 残念ながら素直な書き方で関数引数モドキを... 返事を書く
SECOND 2006/12/06 18:40:33
具体的な問題と例文を出されては、いかがでしょうか。
個別なケースにおいては、思いがけない解決法が隠れているかも?
知れません。

     └一つの解決策として、関数を引数として渡す... クスクス 2006/12/07 16:55:53  ツリーへ

Re: 具体的な問題と例文を出されては、いかがで... 返事を書く
クスクス 2006/12/07 16:55:53
一つの解決策として、関数を引数として渡すのはあきらめ、関数
の値の表を配列として積分副プログラムに渡すことにしてみまし
た。次はそのサンプルです。積分副プログラムと言っても、積分
の定義に基づいた単なる区分求積です。

      └!cos(t)のtin[0,x]における定積分sn(x)のグ... クスクス 2006/12/07 16:57:21  ツリーへ

Re: 一つの解決策として、関数を引数として渡す... 返事を書く
クスクス 2006/12/07 16:57:21
! cos(t) の t in [0,x] における定積分 sn(x) のグラフ
! ・sn(x)=sin(x)-sin(0)=sin(x) だから、sin(x) のグラフと
!  の一致が期待される。
OPTION BASE 0

LET H = 0.01 ! 小区間サイズ
LET A = -2*PI ! 下端
LET B = 2*PI ! 上端
LET N = CEIL((B-A)/H) ! 選点総数
LET ORG = CEIL((0-A)/H) ! 原点の添字

LET X1 = SGN(A)*CEIL(ABS(A)) ! 描画ウィンドウの準備
LET X2 = SGN(B)*CEIL(B)
LET Y1 = -3
LET Y2 = 3
SET WINDOW X1,X2, Y1,Y2
DRAW GRID

DIM TBL(0 TO N, 0 TO 1) ! 被積分函数の選点における値の表

!! cos(t) の [A,B] における数値の表 TBL(,) の作成
LET I=0
FOR I=0 TO N
LET X = A+H*I
LET TBL(I,0) = X
LET TBL(I,1) = COS(X)
NEXT I

!! cos(t) の [0,x] における定積分 sn(x) を x in [A,B] において○で描く(50個の点)
SET POINT STYLE 4
SET POINT COLOR 4
FOR I=0 TO N STEP IP(N/50)
PLOT POINTS: TBL(I,0),RIEMANN_SUM(TBL,ORG,I) ! cos(t) の t in [0, TBLI,0]] での積分値
NEXT I

!! sin(x) の [A,B] におけるグラフを線で描く
SET LINE COLOR 4
FOR X=A TO B STEP H
PLOT LINES: X,SIN(X)
NEXT X

!! 表題の表示
PLOT TEXT, AT X1+(X2-X1)*0.01,Y2-(Y2-Y1)*0.05: "線: sin(x), ○: cos(t) の t in [0,x] での定積分 sn(x)"
END

! リーマン和の計算
! ・TBL(,): 被積分函数の選点における値の配列
! ・M: 積分区間下端添字, N: 積分区間上端添字
EXTERNAL FUNCTION RIEMANN_SUM(TBL(,), M, N)
IF N<M THEN
LET TMP = M
LET M = N
LET N = TMP
LET SIGN = -1
ELSE
LET SIGN =1
END IF

LET SUM = 0
FOR I=M TO N-1
LET SUM = SUM + TBL(I,1)*(TBL(I+1,0)-TBL(I,0)) ! TBL(I,1): 函数の点TBL(I,0)での値
! TBL(I+1,0)-TBL(I,0): 小区間の長さ
NEXT I
LET RIEMANN_SUM = SIGN*SUM
END FUNCTION

       ├!確かにdef定義の名前が引数に置けなくて残... SECOND 2006/12/07 21:25:39  ツリーへ

Re: !cos(t)のtin[0,x]における定積分sn(x)のグ... 返事を書く
SECOND 2006/12/07 21:25:39
!確かにdef定義の名前が引数に置けなくて残念ですね。
!たいして、ひらめきも無くて申訳ないですが、
!気が付いた分を書いておきます。SUM2 SUM3
!「方向単位」は、漢字のままで走ります。

!-----------------------------------------
!swap M,N をしないで、極性ぐるみで和をとる。

EXTERNAL FUNCTION RIEMANN_SUM2(TBL(,), M, N)
LET 方向単位 = SGN(N-M)
LET SUM = 0
FOR I=M TO N-方向単位 STEP 方向単位
LET SUM = SUM + TBL(I,1)*(TBL(I+方向単位,0)-TBL(I,0))
NEXT I
LET RIEMANN_SUM2 = SUM
END FUNCTION

!-----------------------------------------
!精度が良くする。

EXTERNAL FUNCTION RIEMANN_SUM3(TBL(,), M, N)
LET 方向単位 = SGN(N-M)
LET SUM = 0
FOR I=M TO N-方向単位 STEP 方向単位
LET Yav = ( TBL(I,1)+TBL(I+方向単位,1) )/2
LET SUM = SUM + Yav*(TBL(I+方向単位,0)-TBL(I,0))
NEXT I
LET RIEMANN_SUM3 = SUM
END FUNCTION

       │└なるほど、M,Nをswapするよりコードがすっき... クスクス 2006/12/08 19:40:46  ツリーへ

Re: !確かにdef定義の名前が引数に置けなくて残... 返事を書く
クスクス 2006/12/08 19:40:46
なるほど、M,Nをswapするよりコードがすっきりしますね。step
を、方向単位にするだけでなく、Forの実行範囲をN-方向単位と
するのがコツですか。わたしは、単純に手計算をコード化したの
で長くなりました。代表値を平均にとらなかったのはサボリで
す。コードが大して複雑になるわけでもないので、やはり平均は
取った方が良いでしょうね。

       │ └!上書き、御免。 SECOND 2006/12/08 21:05:38  ツリーへ

Re: なるほど、M,Nをswapするよりコードがすっき... 返事を書く
SECOND 2006/12/08 21:05:38
!上書き、御免。

! 方形と台形とでは、1000倍もの誤差の違いが有りました。(A=-1.2*PIは移動具合のテスト)

! cos(x) の a~x における 配列定積分 [TBL(i,2)]a~x のグラフは、
! y=sin(x)-sin(a) のグラフと の一致が期待される。
OPTION BASE 0

LET dx= 0.01 ! 小区間サイズ
LET A =-1.2*PI ! 下端
LET B = 2*PI ! 上端
LET N = CEIL((B-A)/dx) ! 選点総数
DIM TBL(N, 2) ! 被積分函数の選点での値の表 ,0)=x ,1)=f(x) ,2)=∫f(x)[a~x]

LET X1= INT(A) ! =floor(A)と同じ。 ! 描画ウィンドウの準備
LET X2= CEIL(B)
LET Y1=-3
LET Y2= 3
SET WINDOW X1,X2, Y1,Y2
SET COLOR MIX(15) 0.4,0.4,0.4 !グリッドを濃くする。
DRAW GRID

!---- cos(x) 関数の定義、TBL(,) 配列関数化[A~B]=[0~N] と、配列 定積分。
DEF f(x)= COS(x)
FOR I= 0 TO N
LET X= A+dx*I
LET TBL(I,0)= X
LET TBL(I,1)= f(X)
NEXT I
CALL integ台形(TBL,N) !区間[A,B]=[0~N] の定積分。描画せず配列 TBL(I,2) に返します。
!CALL integ方形(TBL,N) !同様。


!---- 結果の描画、区間[A,B]x → TBL(0~N ,2) にて点線印○で描く(50個の点)
SET POINT STYLE 4
SET POINT COLOR 4
FOR I=0 TO N STEP IP(N/50)
LET X=TBL(I,0)
PLOT POINTS: X,TBL(I,2)
NEXT I
!---- 比較 定積分[∫f(x)dx]a~x = sin(x)-sin(a) を、曲線で描く
FOR I=0 TO N STEP IP(N/50)
LET X=TBL(I,0)
PLOT LINES: X, SIN(X)-SIN(A);
NEXT I


!---- 配列積分[A,B] における誤差を、20000 倍で描く、点線印 X 。
SET POINT STYLE 5
SET POINT COLOR 2
FOR I=0 TO N STEP IP(N/50)
LET X=TBL(I,0)
PLOT POINTS: X, 20000*(TBL(I,2)-SIN(X)+SIN(A)) !台形
!PLOT POINTS: X, 20*(TBL(I,2)-SIN(X)+SIN(A)) !方形
NEXT I

!! 表題の表示
SET AREA COLOR 0
PLOT AREA:X1,Y2;X2,Y2;X2,Y2-(Y2-Y1)*0.06;X1,Y2-(Y2-Y1)*0.06
PLOT TEXT, AT X1+(X2-X1)*0.05,Y2-(Y2-Y1)*0.05: "曲線:sin(x)-sin(a)、○:配列関数cos(x)[a~x]定積分、X:誤差20000倍"

END

! リーマン和の計算
! ・TBL(,): 被積分函数の選点における値の配列
!  TBL(I,0): f(x)の、  I での x 値
!  TBL(I,1): f(x)の、  I での f(x)値
!  TBL(I,2): [F(x)]a~x I での 配列 定積分(リターン引数として返す)
! ・区間 I [0~N] は、区間 x [A~B] に対応。

EXTERNAL SUB integ台形(TBL(,), N)
LET SUM = 0
FOR I=1 TO N
LET Yav = ( TBL(I,1)+TBL(I-1,1) )/2
LET SUM = SUM + Yav*(TBL(I,0)-TBL(I-1,0))
LET TBL(I,2)=SUM
NEXT I
END SUB

EXTERNAL SUB integ方形(TBL(,), N)
LET SUM = 0
FOR I=1 TO N
LET SUM = SUM + TBL(I,1)*(TBL(I,0)-TBL(I-1,0))
LET TBL(I,2)=SUM
NEXT I
END SUB

       │  └定義による数値積分の性能が悪いことが分か... クスクス 2006/12/10 16:58:15  ツリーへ

Re: !上書き、御免。 返事を書く
クスクス 2006/12/10 16:58:15
定義による数値積分の性能が悪いことが分かっているとは言えここまでとはね(w
通常の滑らかな関数の数値積分では、台形則、シンプソン則等の数値積分の
公式の利用が必須であることの説明に使えそうですね。

       ├このように記述するのではまずいのですか? 山中和義 2006/12/07 21:58:09  ツリーへ

Re: !cos(t)のtin[0,x]における定積分sn(x)のグ... 返事を書く
山中和義 2006/12/07 21:58:09
このように記述するのではまずいのですか?

!∫cos(x)dx=sin(x)+C
! [0,x]における定積分 ∫[0,x]cos(x)dx=sin(x)-sin(0)=sin(x)だから、レーマン和、台形法で求める。

LET a=-2*PI !積分区間の下限
LET b=2*PI !積分区間の上限
LET N=200 !区間[a,b]の分割数

SET WINDOW -8,8,-3,3 !描画領域
DRAW GRID !座標

LET H=(b-a)/N

FOR x=a TO b STEP H
PLOT LINES: x,RIEMANN(a,x,N);
!PLOT LINES: x,DAIKEI(a,x,N);
NEXT x
PLOT LINES


DEF sF(x)=SIN(x) !原始関数で確認する
SET LINE COLOR 4
FOR x=a TO b STEP H !上書きで黒い線は消える
PLOT LINES: x,sF(x);
NEXT x
PLOT LINES

END

EXTERNAL FUNCTION f(t) !被積分関数
LET f=COS(t)
END FUNCTION

!a:積分区間の下限
!b:積分区間の上限
!N:区間[a,b]の分割数
EXTERNAL FUNCTION RIEMANN(a,b,N) !リーマン和
LET S=0
LET H=(b-a)/N
FOR i=1 TO N
LET x=a+H*i
LET S=S+H*f(x)
NEXT i
LET RIEMANN=S !積分結果 ∫[a,b]f(x)dx
END FUNCTION

EXTERNAL FUNCTION DAIKEI(a,b,N) !台形法
LET S=0
LET H=(b-a)/N
LET x=a
LET F1=f(x)
FOR i=1 TO N
LET x=a+H*i
LET F2=f(x)
LET S=S+0.5*H*(F1+F2)
LET F1=F2
NEXT i
LET DAIKEI=S
END FUNCTION

       └文字列で関数を渡す。ひょっとして、こうい... 山中和義 2006/12/08 12:46:32  ツリーへ

Re: !cos(t)のtin[0,x]における定積分sn(x)のグ... 返事を書く
山中和義 2006/12/08 12:46:32
文字列で関数を渡す。ひょっとして、こういうこと?

付属のINTERPR.BAS(SAMPLEフォルダ内)を改良してみました。

!∫cos(x)dx=sin(x)+C をレーマン和、台形法で求める。
! ※[0,x]における定積分 ∫cos(x)dx=sin(x)-sin(0)=sin(x) だから、
!  sin(x)のグラフとの一致が期待される。

LET a=-2*PI !積分区間の下限
LET b=2*PI !積分区間の上限
LET N=200 !区間[a,b]の分割数

SET WINDOW -8,8,-3,3 !描画領域
DRAW GRID !座標

LET H=(b-a)/N

LET F$="cos(x)" !被積分関数
!LET F$="sin(x)" !被積分関数

FOR i=0 TO N
LET x=a+H*i
PLOT LINES: x,RIEMANN(F$,a,x,N);
!PLOT LINES: x,DAIKEI(F$,a,x,N);
NEXT i
PLOT LINES


SET LINE COLOR 4
FOR i=0 TO N !上書きで黒い線は消える
LET x=a+H*i
PLOT LINES: x,SIN(x); !原始関数で確認する
!PLOT LINES: x,-COS(x)+COS(-2*PI); !原始関数で確認する
NEXT i
PLOT LINES

END


!a:積分区間の下限
!b:積分区間の上限
!N:区間[a,b]の分割数
EXTERNAL FUNCTION RIEMANN(F$,a,b,N) !リーマン和
LET S=0
LET H=(b-a)/N
FOR i=1 TO N
LET x=a+H*i
LET S=S+H*eval(F$,x) !Σh*f(x)
NEXT i
LET RIEMANN=S !積分結果 ∫[a,b]f(x)dx
END FUNCTION

EXTERNAL FUNCTION DAIKEI(F$,a,b,N) !台形法
LET S=0
LET H=(b-a)/N
LET x=a
LET F1=eval(F$,x)
FOR i=1 TO N
LET x=a+H*i
LET F2=eval(F$,x)
LET S=S+H*(F1+F2)/2 !Σh*{f(x1)+f(x2)}/2
LET F1=F2
NEXT i
LET DAIKEI=S
END FUNCTION

        ├つづき 山中和義 2006/12/08 12:49:08  ツリーへ

Re: 文字列で関数を渡す。ひょっとして、こうい... 返事を書く
山中和義 2006/12/08 12:49:08
つづき

EXTERNAL FUNCTION eval(s$,x) !変数xを含む数式の構文解析と実行
DECLARE FUNCTION expression, numeric, term, factor, primary
DECLARE SUB SKIP

LET s$=UCASE$(s$) !すべて大文字に変換
LET i=1 !文字位置
CALL SKIP
LET eval=expression !数式を処理する
IF i<LEN(s$) THEN PRINT "Syntax error"

SUB SKIP !空白を読み飛ばす
DO WHILE s$(i:i)=" "
LET i=i+1
LOOP
END SUB

FUNCTION expression !式
LOCAL n
LOCAL op$
SELECT CASE s$(i:i) !符号
CASE "-"
LET i=i+1
CALL skip
LET n=-term
CASE "+"
LET i=i+1
CALL skip
LET n=term
CASE ELSE
LET n=term
END SELECT
DO WHILE s$(i:i)="+" OR s$(i:i)="-" !加算、減算
LET op$=s$(i:i)
LET i=i+1
CALL skip
IF op$="+" THEN LET n=n+term ELSE LET n=n-term
LOOP
LET expression=n
CALL skip
END FUNCTION

FUNCTION term !項
LOCAL n
LOCAL op$
LET n=factor
DO WHILE s$(i:i)="*" OR s$(i:i)="/" !乗算、除算
LET op$=s$(i:i)
LET i=i+1
CALL skip
IF op$="*" THEN LET n=n*factor ELSE LET n=n/factor
LOOP
LET term=n
END FUNCTION

FUNCTION factor !因子
LOCAL n
LET n=primary
DO WHILE s$(i:i)="^" !べき乗
LET i=i+1
CALL skip
LET n=n^primary
LOOP
LET factor=n
END FUNCTION

        └さらに、つづき 山中和義 2006/12/08 12:50:34  ツリーへ

Re: 文字列で関数を渡す。ひょっとして、こうい... 返事を書く
山中和義 2006/12/08 12:50:34
さらに、つづき

FUNCTION primary !呼び出し
IF s$(i:i)>="0" AND s$(i:i)<="9" THEN !数字
LET primary=NUMERIC
ELSEIF s$(i:i+1)="PI" THEN
LET i=i+2
CALL SKIP
LET primary=PI
ELSEIF s$(i:i)="X" THEN !変数
LET i=i+1
CALL SKIP
LET primary=x
ELSE
IF s$(i:i)="(" THEN !カッコ
LET i=i+1
CALL SKIP
LET primary=expression
ELSEIF s$(i:i+3)="SIN(" THEN !関数
LET i=i+4
CALL SKIP
LET Primary=SIN(expression)
ELSEIF s$(i:i+3)="COS(" THEN
LET i=i+4
CALL SKIP
LET Primary=COS(expression)
ELSEIF s$(i:i+3)="TAN(" THEN
LET i=i+4
CALL SKIP
LET Primary=TAN(expression)
ELSEIF s$(i:i+3)="LOG(" THEN
LET i=i+4
CALL SKIP
LET Primary=LOG(expression)
ELSEIF s$(i:i+3)="EXP(" THEN
LET i=i+4
CALL SKIP
LET Primary=EXP(expression)
ELSEIF s$(i:i+3)="SQR(" THEN
LET i=i+4
CALL SKIP
LET Primary=SQR(expression)
ELSEIF s$(i:i+3)="INT(" THEN
LET i=i+4
CALL SKIP
LET Primary=INT(expression)
ELSEIF s$(i:i+3)="ABS(" THEN
LET i=i+4
CALL SKIP
LET Primary=ABS(expression)
ELSE
PRINT "Syntax error"
STOP
END IF
IF s$(i:i)=")" THEN
LET i=i+1
CALL skip
ELSE
PRINT "Syntax error"
STOP
END IF
END IF
END FUNCTION

FUNCTION numeric !数字
LOCAL i0
CALL skip
LET i0=i
DO WHILE s$(i:i)>="0" AND s$(i:i)<="9"
LET i=i+1
LOOP
IF s$(i:i)="." THEN LET i=i+1
DO WHILE s$(i:i)>="0" AND s$(i:i)<="9"
LET i=i+1
LOOP
LET numeric=VAL(s$(i0:i-1))
CALL skip
END FUNCTION

END FUNCTION

         └こんなサンプルがあったんですか。manにない... クスクス 2006/12/08 20:13:24  ツリーへ

Re: さらに、つづき 返事を書く
クスクス 2006/12/08 20:13:24
こんなサンプルがあったんですか。manにないので気付きませんで
した。問題によっては、このインタプリタは使えますね。ただ、
本物の関数引数と違って、これを使うと呼び出しのたびに数式
を評価するパーサーが起動されオーバーヘッドが発生します。
繰り返し回数の多いループ内からの呼び出しには多分使えないで
しょう。


インデックスへ EXIT
新規発言を反映させるにはブラウザの更新ボタンを押してください。