ab.com コミュニティ

ActiveBasicを通したコミュニケーション
現在時刻 - 2024年3月30日(土) 00:49

全ての表示時間は UTC+09:00 です




新しいトピックを投稿する  トピックへ返信する  [ 15 件の記事 ] 
作成者 メッセージ
投稿記事Posted: 2005年12月03日(土) 13:19 
任意の数学関数、例えばY=AX+Bの式をエディトボックスに書き、さらに
第2のエディトボックスにXを与えると、Yの値を計算して表示する、
ということをやりたいのですが、プログラムをどう書けばよいのか全く見当
がつきません。どなたか教えて下さい。使いたい数学関数はべき乗,sin,cos,
など関数電卓にある程度の初等関数の範囲です。


通報する
ページトップ
   
投稿記事Posted: 2005年12月03日(土) 13:59 
オフライン

登録日時: 2005年5月31日(火) 09:34
記事: 141
お住まい: 北海道
引用:
任意の数学関数、例えばY=AX+Bの式をエディトボックスに書き、さらに
第2のエディトボックスにXを与えると、Yの値を計算して表示する、
ということをやりたいのですが、プログラムをどう書けばよいのか全く見当
がつきません。どなたか教えて下さい。使いたい数学関数はべき乗,sin,cos,
など関数電卓にある程度の初等関数の範囲です。
これはかなり難しい問題です。私も挑戦していますが何度も挫折しています。
ただ,これができれば最終的にはインタプリタやコンパイラへの発展も可能ですがね。

_________________
' ============================================================
' Sinryow Game Home Page - http://www.sinryow.net/
' Sinryow ActiveBasic Center - http://ab.sinryow.net/
' ============================================================


通報する
ページトップ
 記事の件名:
投稿記事Posted: 2005年12月03日(土) 14:49 
一年ほど前逆ポーランドの解説用に適当に作ったHSP3のサンプルですが
ActiveBasicではスタックなども楽に扱えそうなので参考になれば幸いです。
コード:
;==============================================================================
    sdim Sinp
    screen 0,320,200
    ss=""      :objsize 40,19
    pos  10,10 :input   Sinp,260,20 :pos 270,09 :button "CALC",*Scalc
    pos  10,30 :input   ss  ,260,20 :pos  10,50 :input   ss   ,260,20
stop
;------------------------------------------------------------------------------
*Scalc
    gosub *Chrpn  :ss=""
    foreach Sout  :if Sout(cnt) != "" {ss+=Sout(cnt)+" "} :loop :objprm 2,ss
    gosub *Rcalc  :ss=str(double(refstr))
                   if ss == "9999999999.999998" {ss="[0] 除算"} :objprm 3,ss
stop
;==============================================================================
*Chrpn
    sdim Sout :dim pn :sdim Stak :dim sn :sdim Tken :dim pp     :jj=0 :sw=0
    repeat strlen(Sinp)
        ss=strmid(Sinp,cnt,1) :ii=peek(ss,0)
        if (ii == 46) | ((ii >= 48) & (ii <= 57)) {
                                         Tken(jj  )+=ss         :sw=0}
            else {if ss != " " {if sw=0 {Tken(jj+1) =ss :jj+=2  :sw=1}
                                   else {Tken(jj  ) =ss :jj++   :sw=1}}}
    loop
    foreach Tken
        ss=Tken(cnt) :gosub *Ckpri :pp(0)=stat:
        switch pp(0)
            case 5  :Sout(pn)=Tken(cnt)                         :pn++ :swbreak
            case 2  :Stak(sn)=Tken(cnt)                         :sn++ :swbreak
            case 1  :if sn == 0 {break}
                     For jj,sn-1,-1,-1
                        if Stak(jj) ==  "(" {_break}
                        Sout(pn)=Stak(jj) :Stak(jj)=""  :pn++   :sn-- :next
                                          :Stak(jj)=""          :sn-- :swbreak
            default :sw=0
                     For jj,sn-1,-1,-1
                        if (sn == 0) | (sw == 1) {_break}
                            ss=Tken(cnt) :gosub *Ckpri  :pp(1)=stat
                            ss=Stak(jj ) :gosub *Ckpri  :pp(2)=stat
                        if (pp(1) > pp(2)){sw=1}
                                     else {Sout(pn)=Stak(jj)    :pn++ 
                                           Stak(jj)=""          :sn--}:next
                             sn++:Stak(sn)=Tken(cnt)            :sn++ :swbreak
        swend
    loop
    repeat sn-1 :Sout(pn+cnt+1)=Stak(((sn-1)-cnt)) :loop
return
;------------------------------------------------------------------------------
*Ckpri
    switch peek(ss,0)
        case 46 :                                                  ;.
        case 48 :case 49 :case 50 :case 51 :case 52
        case 53 :case 54 :case 55 :case 56 :case 57 :kk=5 :swbreak ;0-9
        case 42 :case 47                            :kk=4 :swbreak ;*/
        case 43 :case 45                            :kk=3 :swbreak ;+/
        case 40                                     :kk=2 :swbreak ;(
        case 41                                     :kk=1 :swbreak ;)
        default                                     :kk=0
    swend
return kk
;------------------------------------------------------------------------------
*Rcalc
    foreach Sout
        ss=Sout(cnt)
        switch ss
            case "*"
                gosub *Pop
                Sout(cnt-ii)=str(double(Sout(cnt-ii))*double(Sout(cnt-jj)))
                Sout(cnt   )="" :Sout(cnt-jj)="" :swbreak
            case "/"
                gosub *Pop
                if double(Sout(cnt-jj)) == 0 {
                          Sout(0)="9999999999.999998" :break}
                Sout(cnt-ii)=str(double(Sout(cnt-ii))/double(Sout(cnt-jj)))
                Sout(cnt   )="" :Sout(cnt-jj)="" :swbreak
            case "+"
                gosub *Pop
                Sout(cnt-ii)=str(double(Sout(cnt-ii))+double(Sout(cnt-jj)))
                Sout(cnt   )="" :Sout(cnt-jj)="" :swbreak
            case "-"
                gosub*Pop
                Sout(cnt-ii)=str(double(Sout(cnt-ii))-double(Sout(cnt-jj)))
                Sout(cnt   )="" :Sout(cnt-jj)="" :swbreak
            default
        swend
    loop
return str(double(Sout(0)))
*Pop
    for ii,1   ,cnt+1 :if Sout(cnt-ii) != "" {_break} :next :jj=ii
    for ii,jj+1,cnt+1 :if Sout(cnt-ii) != "" {_break} :next
return


通報する
ページトップ
   
投稿記事Posted: 2005年12月03日(土) 23:36 
初めまして 関数男様、KICOと申します。
今後共、宜しくお願いします。

数学関数とは、言いがたいですが算数式程度なら出来そうです。
括弧有りの計算は出来ませんが・・・。


通報する
ページトップ
   
投稿記事Posted: 2005年12月06日(火) 16:04 
皆様、お返事をありがとうございました。これは、難しい問題なのですね。 アルゴリズムが全く分からないのですが、世の中にいろいろ数学ソフトがあり、数式を入れれば関数値を計算してプロットしてくれますよね。 一体どうやっているのでしょうか。
 こんなことするのかなあと、思いつくのは、文字列で与えられた関数式から順に"+"とか"-"とか"sin"とか"("とかを検索してそれらの引数も検索して、各関数の値を求め、最後にそれらを合成する… ですが、かなり大変そうに見えます。 どう考えればよいのか、アルゴリズムを知りたいです。


通報する
ページトップ
   
 記事の件名:
投稿記事Posted: 2005年12月06日(火) 17:04 
オフライン

登録日時: 2005年12月06日(火) 15:53
記事: 9
私も昔、VisualBasicでWindows付属の関数電卓と同じようなものを作ってました。
最後にそれらを合成する・・・そのアルゴリズムといえるかどうかは不明ですが式を書いてその結果を出力するものは、式を数字と記号をわけて配列にいれ、配列の前のほうから順次計算していきます。(記号があればそのすぐあとの数字をその記号にしたがって計算します)ただし、+-のときは次に+-があるまで待ちます。
たとえば、2+4×3-10のときは、配列に代入しながら内容を見ていくと
配列の番号:内容
1:2
2:+
はじめの記号は+なので+-があるまで計算しない。
3:4
4:×
5:3
次の記号は×なので次の数3を4にかける。答えを配列3に代入
3:12
4:-
-がきたので前の+を処理する。配列1に2+12の結果を代入直後の配列2に-を代入
1:14
2:-
-なので次に+-がくるまで処理しない
3:10
あとに式がないので計算し値を表示

簡単にこんな流れでしょうか。

関数電卓かなんかをお持ちでしたら、その取り扱い説明書に括弧が入ったときの計算するアルゴリズムの説明(結局は逆ポーランド式のひとことで終わるかもしれませんが)がもっと詳しく書かれていると思います。Xを用いた関数であればそのXの部分に、入力された数字や関数を置換すればよいと思います。参考になれば幸いです。


通報する
ページトップ
投稿記事Posted: 2005年12月06日(火) 17:32 
すみません、消し忘れていました。

それと、書き忘れていましたがEditBox2は、複数行にチェックし、適当な縦サイズを確保して下さい。

括弧演算も含め演算優先順位のルーチェンやトークンチェックは、関数男様の方で入れて下さい。


コード:
			Select Case a\6
				Case 0
					ans[ac]=Sin(Val(d))
				Case 1
					ans[ac]=Cos(Val(d))
				Case 2
					ans[ac]=Tan(Val(d))
			End Select
			ans[ac]=Sin(Val(d)) <---- 削除して下さい。
			ac=ac+1: odc=odc+1
		Else
引用:
世の中にいろいろ数学ソフトがあり、数式を入れれば関数値を計算してプロットしてくれますよね。 一体どうやっているのでしょうか。
定形型と任意型の二つに大別出来るかと?
定形型の場合、数式を選択して変数(x,y,a…)に値を入れて計算する。
任意型の場合、計算する前に、括弧が対に成っているかスペルは間違っていないか
トークンチェックをし演算の優先順位を考えて計算する。
関数男様の仰る通りかなり大変です。


通報する
ページトップ
   
 記事の件名:
投稿記事Posted: 2005年12月06日(火) 18:01 
みなさま助言をありがとうございます。
KICO様、もう少し詳しく教えて頂けると助かります。
<
定形型と任意型の二つに大別出来るかと?
定形型の場合、数式を選択して変数(x,y,a…)に値を入れて計算する。
任意型の場合、計算する前に、括弧が対に成っているかスペルは間違っていないか
トークンチェックをし演算の優先順位を考えて計算する。
(トークンチェック、って?)


通報する
ページトップ
   
 記事の件名:
投稿記事Posted: 2005年12月06日(火) 18:15 
> (トークンチェック、って?)

割り込みですが本格的には「yacc・パーサ」で検索
(ActiveBasicやVisualBasicで簡単に利用したいならGOLDが便利です)

参考URL http://kmaebashi.com/index.html


通報する
ページトップ
   
投稿記事Posted: 2005年12月06日(火) 21:26 
引用:
(トークンチェック、って?)
字句解析・語句解析の事で、任意に入力した数式の先頭から一文字ずつ文末まで解析する事です。

例えば、"Sin"が関数なのか変数なのか使用出来る「関数テーブル」を作りそこに無ければ、「変数テーブル」をみる、
あれば変数、無ければ "タイプミス"エラー というふうに語句解析していきます。

フローチャートを書いて解析していくと解り易いですよ。


通報する
ページトップ
   
 記事の件名:
投稿記事Posted: 2005年12月07日(水) 10:47 
なるほど分かりました。ありがとうございました。


通報する
ページトップ
   
 記事の件名:
投稿記事Posted: 2005年12月07日(水) 16:06 
オフライン

登録日時: 2005年5月31日(火) 22:17
記事: 27
お住まい: 山口
インタープリターもどきです。
といっても代入文のみ。
使用できるのは,(),+,-,/,*,Sin,Cosです。
変数はA-Zで、代入文を実行した瞬間buffer2に答えが入ります。

EditBox1とEditBox2とCommandButton1を使った例です。 EditBox1に
X=10
A=5
Y=A*X+10
としてCommandButton1を押すと
EditBox2に
X=10
A=5
Y=60
と表示されると思います。

_________________
今日も元気にABLife


通報する
ページトップ
 記事の件名:
投稿記事Posted: 2005年12月07日(水) 16:52 
サンプルをありがとうございました。
やはり、プログラムはかなりのものになるのですね。
勉強して頑張ってみます。


通報する
ページトップ
   
投稿記事Posted: 2005年12月07日(水) 20:25 
白石先生による十進BASICでサンプルに入っているアルゴリズムです。
関数についても同様に拡張できます。

REM Full BASICの文法にしたがって数値式を評価するプログラム
REM 数値は整数のみが書ける。 組込み関数や変数は使えない。
REM 零除算エラーなどは考慮していない。
DECLARE EXTERNAL FUNCTION interpreter.expression ! 数値式を評価する関数
DECLARE EXTERNAL STRING interpreter.s$ ! 入力行
DECLARE EXTERNAL NUMERIC interpreter.i ! 入力行の文字位置
DECLARE EXTERNAL SUB interpreter.skip ! 空白文字を読み飛ばす副プログラム
LINE INPUT s$
LET i=1
CALL skip
PRINT expression
IF i<LEN(s$) THEN PRINT "Syntax error at """ ;s$(i: LEN(s$)); """"
END

MODULE interpreter
PUBLIC STRING s$
PUBLIC NUMERIC i
PUBLIC FUNCTION expression
PUBLIC SUB skip
SHARE FUNCTION term,factor,primary,numeric

EXTERNAL SUB skip
DO WHILE s$(i:i)=" "
LET i=i+1
LOOP
END SUB

EXTERNAL FUNCTION expression
DECLARE NUMERIC n
DECLARE STRING 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

EXTERNAL FUNCTION term
DECLARE NUMERIC n
DECLARE STRING 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

EXTERNAL FUNCTION factor
DECLARE NUMERIC 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

EXTERNAL FUNCTION primary
IF s$(i:i)="(" THEN
LET i=i+1
CALL skip
LET primary=expression
IF s$(i:i)=")" THEN
LET i=i+1
CALL skip
ELSE
PRINT "Syntax error"
STOP
END IF
ELSE
LET primary=numeric
END IF
END FUNCTION

EXTERNAL FUNCTION numeric
DECLARE NUMERIC i0

CALL skip
LET i0=i
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 MODULE


通報する
ページトップ
   
 記事の件名:
投稿記事Posted: 2005年12月10日(土) 08:47 
WSHを併用するというのはどうでしょうか?。


通報する
ページトップ
   
期間内表示:  ソート  
新しいトピックを投稿する  トピックへ返信する  [ 15 件の記事 ] 

全ての表示時間は UTC+09:00 です


オンラインデータ

このフォーラムを閲覧中のユーザー: BLEXBot & ゲスト[29人]


トピック投稿:  可
返信投稿:  可
記事編集: 不可
記事削除: 不可
ファイル添付: 不可

検索:
ページ移動:  
cron
Powered by phpBB® Forum Software © phpBB Limited
Japanese translation principally by ocean