|
ライブラリーを使ってパーサー(math parser:数式解析器 ?)を作ってみました。
sampleフォルダ内にあるINTERPRE.basのDLL版 ?
vc++2012にてコンパイルしました。
EXPRTKライブラリー(ヘッダーライブラリー) http://partow.net/programming/exprtk/index.html
https://hp.vector.co.jp/authors/VA008683/QA_INPUT.htm
INPUT文でSQR(3)/2とは入力できませんが、SQRT(3)/2となら入力できます。(笑)
三角関数をはじめ指数関数、対数関数が使用できます。
パラメータ(変数)は使えません。
LET A$="SQRT(3)/2"
!!INPUT A$
PRINT PARSER(A$)
PRINT PARSER("SIN(PI/3)")
PRINT PARSER("2^PI")
PRINT PARSER("EXP(PI*LOG(2))")
FOR X=0 TO 180 STEP 15
LET X$="COS("&STR$(X)&"*PI/180)"
PRINT X$;":";PARSER(X$)
NEXT X
END
EXTERNAL FUNCTION PARSER(X$)
OPTION CHARACTER BYTE
IF X$="" THEN
PRINT "ERROR"
STOP
END IF
LET PARSER=PARSER16(LCASE$(X$))
FUNCTION PARSER16(X$)
ASSIGN ".\DLL\parser16.dll","parser16",FPU
END FUNCTION
END FUNCTION
-----------------------------------------------------------------
こちらはパラメータにu,v,w,x,y,zが使用できます。
LET EXPRESSION$="SIN(2*PI/X)"
FOR X=1 TO 10
PRINT X;":";PARSER(EXPRESSION$,U,V,W,X,Y,Z);SIN(2*PI/X)
NEXT X
PRINT INTEGRAL("1/X",1,2,500);LOG(2)
END
EXTERNAL FUNCTION INTEGRAL(A$,A,B,N)
DIM R(0 TO 3)
LET R(0)=3/8
LET R(1)=9/8
LET R(2)=9/8
LET R(3)=3/8
LET H=(B-A)/N/3
FOR K=0 TO N-1
FOR J=0 TO 3
LET X=A+H*(3*K+J)
LET S=S+R(J)*H*PARSER(A$,U,V,W,X,Y,Z)
NEXT J
NEXT K
LET INTEGRAL=S
END FUNCTION
EXTERNAL FUNCTION PARSER(EXPRESSION$,U,V,W,X,Y,Z)
OPTION CHARACTER BYTE
LET U$=PACKDBL$(U)
LET V$=PACKDBL$(V)
LET W$=PACKDBL$(W)
LET X$=PACKDBL$(X)
LET Y$=PACKDBL$(Y)
LET Z$=PACKDBL$(Z)
IF EXPRESSION$="" THEN
PRINT "ERROR"
STOP
END IF
LET PARSER=PARSER16(LCASE$(EXPRESSION$),U$,V$,W$,X$,Y$,Z$)
FUNCTION PARSER16(INPUT$,U$,V$,W$,X$,Y$,Z$)
ASSIGN ".\DLL\parser16_2.dll","parser16",FPU
END FUNCTION
END FUNCTION
parser16_2.cpp
#include <cstdio>
#include <cmath>
#include <string>
#include <exprtk.hpp>
using namespace std;
extern "C" __declspec(dllexport) double parser16(char *input,double *u,double *v,double *w,double *x,double *y,double *z)
{
typedef exprtk::symbol_table<double> symbol_table_t;
typedef exprtk::expression<double> expression_t;
typedef exprtk::parser<double> parser_t;
double val;
string expression_string = input;
symbol_table_t symbol_table;
symbol_table.add_variable("u",*u);
symbol_table.add_variable("v",*v);
symbol_table.add_variable("w",*w);
symbol_table.add_variable("x",*x);
symbol_table.add_variable("y",*y);
symbol_table.add_variable("z",*z);
symbol_table.add_constants();
expression_t expression;
expression.register_symbol_table(symbol_table);
parser_t parser;
if (parser.compile(expression_string,expression)) {
val = expression.value();
return val;
} else
return -99999999.0;
}
-----------------------------------------------------------------
自前の関数を幾つか追加した強化版
PRINT PARSER("GAMMA(1.5)",U,V,W,X,Y,Z);SQR(PI)/2
LET U=4.125
LET V=3
PRINT PARSER("COMB(U,V)",U,V,W,X,Y,Z);COMB(U,V) !'パラメータは u,v,w,x,y,zのみ
PRINT PARSER("COMB(3.125,2.75)",U,V,W,X,Y,Z)
PRINT PARSER("PERM(5.375,3.125)",U,V,W,X,Y,Z)
END
EXTERNAL FUNCTION PARSER(EXPRESSION$,U,V,W,X,Y,Z)
OPTION CHARACTER BYTE
LET U$=PACKDBL$(U)
LET V$=PACKDBL$(V)
LET W$=PACKDBL$(W)
LET X$=PACKDBL$(X)
LET Y$=PACKDBL$(Y)
LET Z$=PACKDBL$(Z)
IF EXPRESSION$="" THEN
PRINT "ERROR"
STOP
END IF
LET PARSER=PARSER16(LCASE$(EXPRESSION$),U$,V$,W$,X$,Y$,Z$)
FUNCTION PARSER16(INPUT$,U$,V$,W$,X$,Y$,Z$)
ASSIGN ".\DLL\parser16_4.dll","parser16",FPU
END FUNCTION
END FUNCTION
実行結果
.886226925452758 .886226925452758
4.5654296875 4.5654296875
1.78944520280366
90.3737984203253
-----------------------------------------------------------------
FPARSERライブラリー http://warp.povusers.org/FunctionParser/fparser.html
こちらはパラメーターを任意に指定できます。
OPTION BASE 0
DIM S(10)
PRINT PARSER("SIN(PI/3)","",1,S)
PRINT PARSER("SQRT(5)","",1,S)
PRINT PARSER("EXP(2*LOG(5))","",1,S)
PRINT PARSER("CBRT(2)","",1,S)
PRINT PARSER("LOG10(2)","",1,S)
FOR X=0 TO 180 STEP 15
LET S(0)=X
PRINT X;":";PARSER("SIN(X*PI/180)","X",1,S)
NEXT X
LET S(0)=4
LET S(1)=3
LET S(2)=-10
LET S(3)=6
LET S(4)=2
LET S(5)=10
LET S(6)=-5
LET S(7)=6
PRINT PARSER("3*A^3+2*B^2+C/5-D*3*E+F/G+H*3","A,B,C,D,E,F,G,H",8,S)
PRINT 3*S(0)^3+2*S(1)^2+S(2)/5-S(3)*3*S(4)+S(5)/S(6)+S(7)*3
INPUT T
LET XX=T
LET S$="(X*X-T)/(2*X)"
!LET S$="(X*X*X-T)/(3*X*X)"
DO
LET X=XX
LET S(0)=X
LET S(1)=T
LET XX=X-PARSER(S$,"X,T",2,S)
LOOP UNTIL ABS(XX-X)<1E-12
PRINT XX
END
EXTERNAL FUNCTION PARSER(INPUT$,PARA$,N,A())
OPTION CHARACTER BYTE
IF INPUT$="" OR N=0 THEN
PRINT "ERROR"
STOP
END IF
LET A$=REPEAT$(CHR$(0),8*N)
FOR I=0 TO N-1
LET A$(8*I+1:8*I+8)=PACKDBL$(A(I))
NEXT I
IF PARA$="" THEN LET PARA$="X"
LET PARSER=PARSER_(LCASE$(INPUT$),LCASE$(PARA$),A$)
FUNCTION PARSER_(INPUT$,PARA$,A$)
ASSIGN ".\DLL\parser.dll","parser16",FPU
END FUNCTION
END FUNCTION
parser.cpp
#include "fparser.hh"
using namespace std;
extern "C" __declspec(dllexport) double parser16(char *input,char *ss,double *val)
{
FunctionParser parser;
parser.AddConstant("pi", 3.1415926535897932384626433);
try {
parser.Parse(input,ss);
return parser.Eval(val);
} catch(...) {
return -99999999.0;
}
}
-----------------------------------------------------------------
LEPTONライブラリー https://simtk.org/projects/lepton
ナント十進BASIC上から導関数が求められるようになりました。
割と複雑な数式にも対応しているようです。
※くれぐれもバッファサイズを超えないように気を付けてください。
超えると多分落ちます。
https://hp.vector.co.jp/authors/VA008683/QA_Limitat.htm
OPTION CHARACTER BYTE
LET PARA$="X" ! Xで微分
DO
READ IF MISSING THEN EXIT DO:F$
DATA "4*X^4+3*X^3-2*X^2+X+1"
DATA "SIN(X)/X"
DATA "LOG(X)"
DATA "X^X"
DATA "SQRT(X)"
DATA "COS(X*SIN(3*X))"
DATA "X^2*EXP(X)"
DATA "COS(1/X)"
DATA "SINH(X)"
DATA "ATAN(X)"
CALL DIFF(F$,PARA$,DIFF$)
PRINT "f(x)=";F$
PRINT "f'(x)=";DIFF$
CALL DIFF(DIFF$,PARA$,DIFF2$)
PRINT "f''(x)=";DIFF2$
PRINT
LOOP
END
EXTERNAL SUB DIFF(INPUT$,PARA$,OUTPUT$)
OPTION CHARACTER BYTE
LET S$=REPEAT$(CHR$(0),5000) !バッファサイズ 5000文字分
CALL DIFF_(LCASE$(INPUT$),LCASE$(PARA$),S$)
FOR I=1 TO LEN(S$)
IF ORD(S$(I:I))<32 THEN EXIT FOR
NEXT I
LET OUTPUT$=S$(1:I-1)
SUB DIFF_(INPUT$,PARA$,OUTPUT$)
ASSIGN ".\DLL\parserdiff.dll","parserdiff"
END SUB
END SUB
parserdiff.cpp
#include <string>
#include <sstream>
#include <cmath>
#include "Lepton.h"
#pragma comment(lib, "lepton.lib")
using namespace std;
extern "C" __declspec(dllexport) void parserdiff(char *input,char *para,char *output)
{
string s;
ostringstream oss;
try {
oss << Lepton::Parser::parse(input).differentiate(para).optimize();
s=oss.str();
strcpy(output,s.c_str());
} catch(...) {
strcpy(output,"error");
}
}
実行結果
f(x)=4*X^4+3*X^3-2*X^2+X+1
f'(x)=1+(((16*(cube(x)))+(9*(square(x))))-(4*(x)))
f''(x)=-4+((48*(square(x)))+(18*(x)))
f(x)=SIN(X)/X
f'(x)=(((x)*(cos(x)))-(sin(x)))/(square(x))
f''(x)=(((square(x))*(((cos(x))-((x)*(sin(x))))-(cos(x))))-((((x)*(cos(x)))-(sin(x)))*(2*(x))))/(square(square(x)))
f(x)=LOG(X)
f'(x)=recip(x)
f''(x)=-(recip(square(x)))
f(x)=X^X
f'(x)=((x)*((x)^(-1+(x))))+((log(x))*((x)^(x)))
f''(x)=(((x)*(((-1+(x))*((x)^(-1+(-1+(x)))))+((log(x))*((x)^(-1+(x))))))+((x)^(-1+(x))))+(((log(x))*(((x)*((x)^(-1+(x))))+((log(x))*((x)^(x)))))+(((x)^(x))/(x)))
f(x)=SQRT(X)
f'(x)=0.5*(recip(sqrt(x)))
f''(x)=0.5*((-0.5*(recip(sqrt(x))))/(square(sqrt(x))))
f(x)=COS(X*SIN(3*X))
f'(x)=-((sin((x)*(sin(3*(x)))))*(((x)*(3*(cos(3*(x)))))+(sin(3*(x)))))
f''(x)=-(((sin((x)*(sin(3*(x)))))*((((x)*(-9*(sin(3*(x)))))+(3*(cos(3*(x)))))+(3*(cos(3*(x))))))+((((x)*(3*(cos(3*(x)))))+(sin(3*(x))))*((cos((x)*(sin(3*(x)))))*(((x)*(3*(cos(3*(x)))))+(sin(3*(x)))))))
f(x)=X^2*EXP(X)
f'(x)=((square(x))*(exp(x)))+((exp(x))*(2*(x)))
f''(x)=(((square(x))*(exp(x)))+((exp(x))*(2*(x))))+((2*(exp(x)))+((2*(x))*(exp(x))))
f(x)=COS(1/X)
f'(x)=(sin(recip(x)))/(square(x))
f''(x)=((-((square(x))*((cos(recip(x)))/(square(x)))))-((sin(recip(x)))*(2*(x))))/(square(square(x)))
f(x)=SINH(X)
f'(x)=cosh(x)
f''(x)=sinh(x)
f(x)=ATAN(X)
f'(x)=recip(1+(square(x)))
f''(x)=(-2*(x))/(square(1+(square(x))))
もちろんニュートン法にも利用できます。
INPUT U
LET XX=U
LET S$="X^2-U"
!LET S$="X^3-U"
!LET S$="X^4-U"
CALL DIFF(S$,"X",DIFF$)
LET F$="("&S$&")/("&DIFF$&")"
PRINT F$
DO
LET X=XX
LET XX=X-PARSER(F$,U,V,W,X,Y,Z)
LOOP UNTIL ABS(XX-X)<1E-12
PRINT XX;SQR(U)
END
EXTERNAL FUNCTION PARSER(INPUT$,U,V,W,X,Y,Z)
OPTION CHARACTER BYTE
LET U$=PACKDBL$(U)
LET V$=PACKDBL$(V)
LET W$=PACKDBL$(W)
LET X$=PACKDBL$(X)
LET Y$=PACKDBL$(Y)
LET Z$=PACKDBL$(Z)
IF INPUT$="" THEN
PRINT "ERROR"
STOP
END IF
LET PARSER=PARSER_(LCASE$(INPUT$),U$,V$,W$,X$,Y$,Z$)
FUNCTION PARSER_(INPUT$,U$,V$,W$,X$,Y$,Z$)
ASSIGN ".\DLL\parser2.dll","parser",FPU
END FUNCTION
END FUNCTION
EXTERNAL SUB DIFF(INPUT$,PARA$,OUTPUT$)
中略
END SUB
BASファイル13本及びソース、dllファイル合わせて26本と使用したライブラリーツール7種を
下記URLにアップしておきました。(parser.zip)
ぜひ、お試しください。
https://13.gigafile.nu/0803-cea376ccc4abf8593dc499561d37001b7
なお、URL有効期限は2019年8月3日(土)までです。
P.S
お願い
数式処理ライブラリーginacというものがあるのですが
今現在のところvc++ビルドには対応していないようです。(MinGw + msys2 or Cygwin)
これを使用すると微分・積分・式の展開などの数式処理ができるようです。
どなたかこのライブラリーを十進BASIC上で(DLLファイルを通して)利用できるようにしてもらえないでしょうか?
Linux上でクロスコンパイル(ビルド)という方法もあるようですが...
https://www.ginac.de/
http://ankokudan.org/d/dl/pdf/pdf-ginac.pdf
https://osdn.net/projects/vc-ginac-cln/releases/
|
|