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

/// \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;
}