C/C++ 数学関数

 投稿者:しばっち  投稿日:2017年 6月18日(日)12時42分46秒
  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ファイル
が混在しています。
 

戻る