|
C/C++で定義されている数学関数を定義してみました。
INPUT Z
LET L=LGAMMA(Z)
PRINT L;EXP(L)
END
EXTERNAL FUNCTION GAMMA(Z)
LET X$=PACKDBL$(Z)
IF Z>0 THEN
LET GAMMA=GAMMA_(X$)
ELSE
IF FP(Z)=0 THEN
PRINT "定義域エラー"
STOP
END IF
LET GAMMA=GAMMA_(X$)
END IF
FUNCTION GAMMA_(X$)
ASSIGN ".\DLL\gamma_.dll","tgamma_",FPU
END FUNCTION
END FUNCTION
EXTERNAL FUNCTION LGAMMA(Z)
LET X$=PACKDBL$(Z)
LET LGAMMA=LGAMMA_(X$)
FUNCTION LGAMMA_(X$)
ASSIGN ".\DLL\gamma_.dll","lgamma_",FPU
END FUNCTION
END FUNCTION
EXTERNAL FUNCTION DIGAMMA(Z)
LET X$=PACKDBL$(Z)
LET DIGAMMA=DIGAMMA_(X$)
FUNCTION DIGAMMA_(X$)
ASSIGN ".\DLL\gamma_.dll","digamma_",FPU
END FUNCTION
END FUNCTION
EXTERNAL FUNCTION TRIGAMMA(Z)
LET X$=PACKDBL$(Z)
LET TRIGAMMA=TRIGAMMA_(X$)
FUNCTION TRIGAMMA_(X$)
ASSIGN ".\DLL\gamma_.dll","trigamma_",FPU
END FUNCTION
END FUNCTION
EXTERNAL FUNCTION POLYGAMMA(N,Z)
LET X$=PACKDBL$(Z)
LET POLYGAMMA=POLYGAMMA_(INT(N),X$)
FUNCTION POLYGAMMA_(N,X$)
ASSIGN ".\DLL\gamma_.dll","polygamma_",FPU
END FUNCTION
END FUNCTION
-------------------------------------------------------------------------------------------
gamma_.cpp
#include <boost/math/special_functions/gamma.hpp>
#include <boost/math/special_functions/digamma.hpp>
#include <boost/math/special_functions/trigamma.hpp>
#include <boost/math/special_functions/polygamma.hpp>
using namespace boost::math;
using namespace std;
extern "C" __declspec(dllexport) double tgamma_(double *a)
{
return tgamma(*a);
}
extern "C" __declspec(dllexport) double lgamma_(double *a)
{
return lgamma(*a);
}
extern "C" __declspec(dllexport) double digamma_(double *a)
{
return digamma(*a);
}
extern "C" __declspec(dllexport) double trigamma_(double *a)
{
return trigamma(*a);
}
extern "C" __declspec(dllexport) double polygamma_(int n,double *a)
{
return polygamma(n,*a);
}
※ご注意
DLL側ではエラー処理をしていません。私自身が定義域をよく理解していませんので。
BASIC側で処理するか、範囲を超えないよう注意してください。
また、1000桁モードで使用できる関数も定義してみました。
OPTION ARITHMETIC DECIMAL_HIGH
LET X=1/5
CALL LATAN(1000,STR$(X),RESULT$)
LET S=16*VAL(RESULT$)
LET X=1/239
CALL LATAN(1000,STR$(X),RESULT$)
LET S=S-4*VAL(RESULT$)
PRINT S
PRINT PI
END
EXTERNAL SUB LATAN(KETA,X$,RESULT$)
OPTION ARITHMETIC DECIMAL_HIGH
LET B$=REPEAT$(CHR$(0),KETA+100)
CALL ATAN1000(KETA,X$,B$)
FOR I=LEN(B$) TO 1 STEP -1
IF B$(I:I)<="9" AND B$(I:I)>="0" THEN
EXIT FOR
END IF
NEXT I
LET RESULT$=B$(1:I)
SUB ATAN1000(KETA,X$,Y$)
ASSIGN ".\DLL\atan1000.dll","atan1000"
END SUB
END SUB
EXTERNAL SUB LACOTAN(KETA,X$,RESULT$)
OPTION ARITHMETIC DECIMAL_HIGH
LET B$=REPEAT$(CHR$(0),KETA+100)
CALL ACOTAN1000(KETA,X$,B$)
FOR I=LEN(B$) TO 1 STEP -1
IF B$(I:I)<="9" AND B$(I:I)>="0" THEN
EXIT FOR
END IF
NEXT I
LET RESULT$=B$(1:I)
SUB ACOTAN1000(KETA,X$,Y$)
ASSIGN ".\DLL\atan1000.dll","acotan1000"
END SUB
END SUB
-------------------------------------------------------------------------------------------
atan1000.cpp
#include <cmath>
#include <string>
#include <boost/multiprecision/mpfr.hpp>
using namespace std;
using namespace boost::multiprecision;
extern "C" __declspec(dllexport) void atan1000(int keta,char *a,char *b)
{
mpfr_float::default_precision(keta);
mpfr_float x,y;
string s;
x.assign(a);
y=atan(x);
s=y.str(keta,true);
strcpy(b,s.c_str());
}
extern "C" __declspec(dllexport) void acotan1000(int keta,char *a,char *b)
{
mpfr_float::default_precision(keta);
mpfr_float x,y;
string s;
x.assign(a);
y=atan(1/x);
s=y.str(keta,true);
strcpy(b,s.c_str());
}
GMP互換ライブラリーを使用しています。
「mpir.dll」「mpfr.dll」をBASIC.EXEと同じフォルダーに入れてください。
http://www.mpfr.org/
下記よりダウンロードしてください。(math.zip)
ダウンロードパス:shibacchi
なお、有効期限は本日より1ヶ月間となります。
P.S
VC++2017でコンパイルした Cファイルは問題なかったのですが、
C++ファイルはBASIC側で「DLLファイルがロードできない」等のエラーが出ました。
仕方なく諦めようかと思いましたが、VC++2010でコンパイルしてみたところ
問題なく動作しました。よってVC++2017とVC++2010でコンパイルしたDLLファイル
が混在しています。
|
|