北太天元軟件上的長10進制數(shù)運算插件制作回顧

/// \file main.cpp
/// \brief?把一個C++實現(xiàn)的長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位小數(shù))
?*/
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的小數(shù)點后保留的位數(shù)設(shè)置為%d\n", (int)value);
?????????return;
??????}
???}
???bxPrintf("BigDecimal的小數(shù)點后保留的位數(shù)設(shè)置沒有成功,保持默認的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;
}