欢迎光临散文网 会员登陆 & 注册

北太天元软件上的长10进制数运算插件制作回顾

2023-02-07 13:24 作者:卢朓  | 我要投稿

/// \file main.cpp

/// \brief 把一个C++实现的长10进制运算的代码做成北太天元的插件

/// \author Tiao Lu, tlu@pku.edu.cn

/// \version 0.1

/// \date 2023-02-07


#include "bex/bex.hpp"

#include "BigDecimal.h"


#include <iostream>


using namespace baltam;



std::string get_string(const bxArray *p) {

 if(bxIsString(p)) {

   const char * chars = bxGetStringDataPr(p);

   int n = bxGetStringLen(p);

   std::string s;

   s.resize(n);

   for(int i = 0; i < n; i++) {

     s[i] = chars[i];

   }

   return s;

 }


 assert(bxIsChar(p));

 int m = bxGetM(p);

 int n = bxGetN(p);

 assert(m == 1);

 std::string s;

 const char *chars = bxGetChars(p);

 s.resize(n);

 for(int i = 0; i < n; i++) {

   s[i] = chars[i];

 }

 return s;

}


/**

 * \brief get_double

 * 获得通用指针p存储的double单个值

 * 期望通用指针p的类型为double matrix,且为单个值.

 */

void get_double(double &x, const bxArray *p) {

 assert(bxIsDouble(p));

 int m = bxGetM(p);

 int n = bxGetN(p);

 assert(m == 1 && n == 1);

 double *mat = bxGetDoubles(p);

 x = mat[0];

 return;

}



int get_double_check(double &x, const bxArray *p) {

   if(!bxIsDouble(p)){

      return 1;

   }   

 int m = bxGetM(p);

 int n = bxGetN(p);

 if( !(m == 1 && n == 1)) return 2;


   get_double(x,p);

   return 0;

}


void set_double(double value, bxArray * &bp) {

   bp = bxCreateDoubleMatrix(1,1, bxREAL);

   double * ptr = bxGetDoubles(bp);

   *ptr = value;


}


void set_bool(bool value, bxArray * &bp) {

   bp = bxCreateLogicalScalar(value);

}


//这里的名字"BigDecimal" 要和库文件main.so( main.dll , maind.dylib)

//在北太天元安装目录下的plugins下面的文件夹的名字相同

#define PLUGIN_NAME "BigDecimal"


using namespace baltam;


void bd_add_B_B(int nlhs, bxArray *plhs[], int nrhs, const bxArray *prhs[]);


struct bBigDecimalP: public extern_obj_base {

   BigDecimal data;

   BALTAM_LOCAL static int ID;

   extern_obj_base *dup() const override;

      bBigDecimalP();

   ~bBigDecimalP() override;

      std::string to_string() const override;

   std::string classname() const override;

};


int bBigDecimalP::ID = 754;


bBigDecimalP::bBigDecimalP() : data(std::string(""))

{

}


extern_obj_base *bBigDecimalP::dup() const {

   return new bBigDecimalP(*this);

}



std::string bBigDecimalP::classname() const {

   return "BigDecimal";

}


std::string bBigDecimalP::to_string() const {

   return data.toString();

}




bBigDecimalP::~bBigDecimalP(){

}



template <typename extObjType,typename packDataType>

void bd_CreateExternalObj(bxArray *plhs[], packDataType &packData )

{

   extObjType * ret = bxNewCXXObject<extObjType>();

   ret->data = packData;

   plhs[0] = bxCreateExtObj(ret);

}




void bd_add_B_B(int nlhs, bxArray *plhs[], int nrhs, const bxArray *prhs[]) {

      if(nlhs!=1)return;

   if(nrhs!=2) return;


   bBigDecimalP *BDP_1 = bxGetExtObj<bBigDecimalP>(prhs[0]);

      if (BDP_1 == nullptr) return;

   bBigDecimalP *BDP_2 = bxGetExtObj<bBigDecimalP>(prhs[1]);

      if (BDP_2 == nullptr) return;


    BigDecimal value = BDP_1->data + BDP_2->data;

   bd_CreateExternalObj<bBigDecimalP,BigDecimal>(plhs,value);

}


void bd_subtract_B_B(int nlhs, bxArray *plhs[], int nrhs, const bxArray *prhs[]) {

      if(nlhs!=1)return;

   if(nrhs!=2) return;


   bBigDecimalP *BDP_1 = bxGetExtObj<bBigDecimalP>(prhs[0]);

      if (BDP_1 == nullptr) return;

   bBigDecimalP *BDP_2 = bxGetExtObj<bBigDecimalP>(prhs[1]);

      if (BDP_2 == nullptr) return;


    BigDecimal value = BDP_1->data - BDP_2->data;

   bd_CreateExternalObj<bBigDecimalP,BigDecimal>(plhs,value);

}


void bd_multiply_B_B(int nlhs, bxArray *plhs[], int nrhs, const bxArray *prhs[]) {

      if(nlhs!=1)return;

   if(nrhs!=2) return;


   bBigDecimalP *BDP_1 = bxGetExtObj<bBigDecimalP>(prhs[0]);

      if (BDP_1 == nullptr) return;

   bBigDecimalP *BDP_2 = bxGetExtObj<bBigDecimalP>(prhs[1]);

      if (BDP_2 == nullptr) return;


    BigDecimal value = BDP_1->data * BDP_2->data;

   bd_CreateExternalObj<bBigDecimalP,BigDecimal>(plhs,value);

}


void bd_divide_B_B(int nlhs, bxArray *plhs[], int nrhs, const bxArray *prhs[]) {

      if(nlhs!=1)return;

   if(nrhs!=2) return;


   bBigDecimalP *BDP_1 = bxGetExtObj<bBigDecimalP>(prhs[0]);

      if (BDP_1 == nullptr) return;

   bBigDecimalP *BDP_2 = bxGetExtObj<bBigDecimalP>(prhs[1]);

      if (BDP_2 == nullptr) return;


    BigDecimal value = BDP_1->data / BDP_2->data;

   bd_CreateExternalObj<bBigDecimalP,BigDecimal>(plhs,value);

}


void bd_mod_B_B(int nlhs, bxArray *plhs[], int nrhs, const bxArray *prhs[]) {

      if(nlhs!=1)return;

   if(nrhs!=2) return;


   bBigDecimalP *BDP_1 = bxGetExtObj<bBigDecimalP>(prhs[0]);

      if (BDP_1 == nullptr) return;

   bBigDecimalP *BDP_2 = bxGetExtObj<bBigDecimalP>(prhs[1]);

      if (BDP_2 == nullptr) return;


    BigDecimal value = BDP_1->data % BDP_2->data;

   bd_CreateExternalObj<bBigDecimalP,BigDecimal>(plhs,value);

}


void bd_pow_B_B(int nlhs, bxArray *plhs[], int nrhs, const bxArray *prhs[]) {

      if(nlhs!=1)return;

   if(nrhs!=2) return;


   bBigDecimalP *BDP_1 = bxGetExtObj<bBigDecimalP>(prhs[0]);

      if (BDP_1 == nullptr) return;

   bBigDecimalP *BDP_2 = bxGetExtObj<bBigDecimalP>(prhs[1]);

      if (BDP_2 == nullptr) return;


    BigDecimal value = BDP_1->data ^ BDP_2->data;

   bd_CreateExternalObj<bBigDecimalP,BigDecimal>(plhs,value);

}


void bd_gt_B_B(int nlhs, bxArray *plhs[], int nrhs, const bxArray *prhs[]) {

      if(nlhs!=1)return;

   if(nrhs!=2) return;


   bBigDecimalP *BDP_1 = bxGetExtObj<bBigDecimalP>(prhs[0]);

      if (BDP_1 == nullptr) return;

   bBigDecimalP *BDP_2 = bxGetExtObj<bBigDecimalP>(prhs[1]);

      if (BDP_2 == nullptr) return;


    bool value = BDP_1->data > BDP_2->data;

      set_bool(value, plhs[0]);

}


void bd_geq_B_B(int nlhs, bxArray *plhs[], int nrhs, const bxArray *prhs[]) {

      if(nlhs!=1)return;

   if(nrhs!=2) return;


   bBigDecimalP *BDP_1 = bxGetExtObj<bBigDecimalP>(prhs[0]);

      if (BDP_1 == nullptr) return;

   bBigDecimalP *BDP_2 = bxGetExtObj<bBigDecimalP>(prhs[1]);

      if (BDP_2 == nullptr) return;


    bool value = BDP_1->data >= BDP_2->data;

      set_bool(value, plhs[0]);

}


void bd_lt_B_B(int nlhs, bxArray *plhs[], int nrhs, const bxArray *prhs[]) {

      if(nlhs!=1)return;

   if(nrhs!=2) return;


   bBigDecimalP *BDP_1 = bxGetExtObj<bBigDecimalP>(prhs[0]);

      if (BDP_1 == nullptr) return;

   bBigDecimalP *BDP_2 = bxGetExtObj<bBigDecimalP>(prhs[1]);

      if (BDP_2 == nullptr) return;


    bool value = BDP_1->data < BDP_2->data;

      set_bool(value, plhs[0]);

}


void bd_leq_B_B(int nlhs, bxArray *plhs[], int nrhs, const bxArray *prhs[]) {

      if(nlhs!=1)return;

   if(nrhs!=2) return;


   bBigDecimalP *BDP_1 = bxGetExtObj<bBigDecimalP>(prhs[0]);

      if (BDP_1 == nullptr) return;

   bBigDecimalP *BDP_2 = bxGetExtObj<bBigDecimalP>(prhs[1]);

      if (BDP_2 == nullptr) return;


    bool value = BDP_1->data <= BDP_2->data;

      set_bool(value, plhs[0]);

}





int bxPluginInit(int, const bxArray*[]){

   //Registe custom class to baltam kernal

   int sid = bxAddCXXClass<bBigDecimalP>(PLUGIN_NAME);


   //Registe custom operate to baltam kernal

   bxRegisterBinaryOperator(PLUGIN_NAME,"+", sid, sid, bd_add_B_B);

   bxRegisterBinaryOperator(PLUGIN_NAME,"-", sid, sid, bd_subtract_B_B);

   bxRegisterBinaryOperator(PLUGIN_NAME,"*", bBigDecimalP::ID, bBigDecimalP::ID, bd_multiply_B_B);

   bxRegisterBinaryOperator(PLUGIN_NAME,"/", sid, sid, bd_divide_B_B);

   bxRegisterBinaryOperator(PLUGIN_NAME,"^", sid, sid, bd_pow_B_B);

   bxRegisterBinaryOperator(PLUGIN_NAME,".^", sid, sid, bd_pow_B_B);

   bxRegisterBinaryOperator(PLUGIN_NAME,">", sid, sid, bd_gt_B_B);

   bxRegisterBinaryOperator(PLUGIN_NAME,">=", sid, sid, bd_geq_B_B);

   bxRegisterBinaryOperator(PLUGIN_NAME,"<", sid, sid, bd_lt_B_B);

   bxRegisterBinaryOperator(PLUGIN_NAME,"<=", sid, sid, bd_leq_B_B);


   return 0;

}


int bxPluginFini(){ return 0; }


void bd_create(int nlhs, bxArray *plhs[], int nrhs, const bxArray *prhs[]){

 if (nlhs > 1){

   return;

   }

   if(nrhs != 1){

      return;

   }


 bBigDecimalP * ret = bxNewCXXObject<bBigDecimalP>();


   if( bxIsString(prhs[0]) || bxIsChar(prhs[0])){

      std::string argv1 = get_string(prhs[0]);

      ret->data = BigDecimal(argv1);

   }

   else{

      double x;

      if(get_double_check(x, prhs[0]) == 0 ){

         ret->data = BigDecimal(x);

      }

   }


 plhs[0] = bxCreateExtObj(ret);

}


void bd_to_string(int nlhs, bxArray *plhs[], int nrhs, const bxArray *prhs[]){

 if (nlhs > 1){

   return;

   }

   if(nrhs != 1){

      return;

   }


 bBigDecimalP * bd = bxGetExtObj<bBigDecimalP>(prhs[0]);

   if (bd == nullptr)

         return;

   std::string ret = bd->data.toString();

 plhs[0] = bxCreateString(ret.c_str());

}


void bd_to_double(int nlhs, bxArray *plhs[], int nrhs, const bxArray *prhs[]){

 if(nlhs > 1) return;

   if(nrhs != 1) return;


 bBigDecimalP * bd = bxGetExtObj<bBigDecimalP>(prhs[0]);

   if (bd == nullptr) return;

   double ret = bd->data.toDouble();

 set_double(ret, plhs[0]);

}


/**

 * 在被北太天元中的使用举例

 * load_plugin("BigDecimal");

 * a = bigdecimal(1); b = bigdecimal(3);

 * a/b

 * 会得到 0.333333333333333333333333333333333333333333333 (总共100位)

 * 如果使用了bd_setscale 例如

 * bd_setscale(5)

 * a/b

 * 会得到 0.33333   (5位小数)

 */

void bd_setscale(int nlhs, bxArray *plhs[], int nrhs, const bxArray *prhs[]){

 if (nlhs > 1) return;

   if(nrhs != 1) return;


   if( bxIsDouble(prhs[0]) || bxIsInt32(prhs[0]) ){

      int err;

      int value = bxAsInt(prhs[0], &err);

      if(err == 0){

         BigDecimal::setscale( (int)value );

         bxPrintf("BigDecimal的小数点后保留的位数设置为%d\n", (int)value);

         return;

      }

   }

   bxPrintf("BigDecimal的小数点后保留的位数设置没有成功,保持默认的100位\n");

}


static bexfun_info_t flist[] = {

   {"bigdecimal", bd_create, nullptr},

   {"bd_create", bd_create, nullptr},

   {"bd_to_string", bd_to_string, nullptr},

   {"bd_setscale", bd_setscale, nullptr},

   {"bd_to_double", bd_to_double, nullptr},

   {"bd_mod", bd_mod_B_B, nullptr},

   {"bd_pow", bd_pow_B_B, nullptr},

   {"bd_gt", bd_gt_B_B, nullptr},

   {"bd_add", bd_add_B_B, nullptr},

   {"bd_subtract", bd_subtract_B_B, nullptr},

   {"bd_multiply", bd_multiply_B_B, nullptr},

   {"bd_divide", bd_divide_B_B, nullptr},

   {"", nullptr, nullptr},

};


bexfun_info_t * bxPluginFunctions(){

   return flist;

}





北太天元软件上的长10进制数运算插件制作回顾的评论 (共 条)

分享到微博请遵守国家法律