GMP库基本使用

参考博客:GMP库使用方法(play maker)

参考博客:GMP函数

准备工作:

先编译好gmp库,make工作估计要花费1-3分钟,如果没有长时间的编译活动请去其他博客查找哪里出了问题。

编译好之后应该有如下效果:

根目录/usr/local/include 下应当有gmp.h,如果附加上c++编译应当有gmpxx.h。

安装的gmp库文件夹(默认是"gmp-版本号"的格式)下有include和lib文件夹。


写代码想要调用gmp.h的话,有三个办法:

一、在.bashrc中添加环境变量

在用户~/目录下打开.bashrc文件,加入:

export LD_LIBRARY_PATH = ~/gmp/gmp-6.2.1/lib:$LD_LIBRARY_PATH

具体文件夹位置要以自己为准。Ctrl+H 查看文件夹下隐藏文件。

但是问题是,我试了这种方法好像没啥用。。。

二、include调用时使用详细的地址:

Linux中头文件都默认放到了“/usr/include/”目录下,我们调用时加上详细地址:

#include "/usr/local/include/gmp.h"

三、编译时使用动态链接库-lgmp

编译命令如下:

gcc % -o %< -L. -lgmp

这样就可直接写成 #include <gmp.h>

gmp库使用

mpz是高精度整数(multiple precision integer),z是整数集的那个\(\mathbb Z\)

mpq是高精度分数(multiple precision fraction),q的含义是quotient(商)。

mpf是高精度浮点数,f的含义是float,由一个任意精度的尾数(mantissa)和一个极限精度的指数(limited precision exponent)构成。

mpq与mpf的区别: mpq可以精确表示浮点数表示不了的分数,比如1/3;mpf则可以表示分数表示不了的无理数。

整数函数以 mpz_ 为前缀,对应的是 mpz_t 类型。

有理数函数以 mpq_ 为前缀,对应于 mpq_t 类型。

浮点数函数以 mpf_ 为前缀,对应于 mpf_t 类型。


下面是函数详解:

1. 定义一个长整数(变量名实际为长整数的地址):

mpz_t A;
printf("A.address = %p\n",A);

mpz_t B[2333];    //定义2333个大整数。

2. 初始化,不初始化一个长整数就使用会运行时段错误。

mpz_init(A);                  //初始化后A值为0;
mpz_inits(A, B, C, D, NULL);  //inits可以初始化多个大整数,但最后要记得加上NULL,否则段错误。

3. 释放操作:

mpz_clear(A);     //清理空间;
mpz_clears(A, B, C, D, NULL);

4. 赋值操作:

void mpz_set(mpz_t x, const mpz_t op);                 //将第二个大整数赋值给第一个。
void mpz_set_q(mpz_t x, const mpq_t op);
void mpz_set_f(mpz_t x, const mpf_t op);
void mpz_set_ui(mpz_t x, const unsigned long op);      //用一个unsigned long范围的正整数赋值给大整数。
void mpz_set_si(mpz_t x, const signed long op);        //用一个long范围的整数赋值给大整数。
void mpz_set_d(mpz_t x, const double op);
int mpz_set_str(mpz_t x, const char* s, int base);     //方便的大整数赋值,将大整数以字符串的形式传进s。

//注意到set_str是int型函数,如果字符串是有效的数字,函数返回0,否则函数返回-1。
//base是进制,如果base为0根据字符串前缀判断,与C语言字面量相似,例如0x是16进制,0b是二进制。
//base不为零时,取值2~62,当base <= 36 时,英文字符不区分大小写;当 37 <= base && base <=62 时,大写字母代表10~35之间的数,小写字母代表36~61。

可以把初始化和赋值连在一起更方便,这个更常用:

void mpz_init_set (mpz t rop, const mpz t op) 
void mpz_init_set_ui (mpz t rop, unsigned long int op) 
void mpz_init_set_si (mpz t rop, signed long int op)
void mpz_init_set_d (mpz t rop, double op)

set是赋值给大整数,get就是大整数转换为一般的C语言数据类型,但要小心溢出:

unsigned long mpz_get_ui(mpz_t op);
signed long mpz_get_si(mpz_t op);
double mpz_get_d(mpz_t op); 
char *mpz_get_str(char *str, int base, mpz_t op);
double mpz_get_d_2exp(signed long * exp, mpt_t op); // 类似于C的 frexp() 函数。

5. mpz_计算:

void mpz_add(mpz_t rop, mpz_t x, mpz_t y);               // rop = x + y;
void mpz_sub(mpz_t rop, mpz_t x, mpz_t y);               // rop = x - y;
void mpz_mul(mpz_t rop, mpz_t x, mpz_t y);               // rop = x * y;
void mpz_neg(mpz_t rop, mpz_t op);                       // rop = -op;
void mpz_abs(mpt_t rop, mpz_t op);                       // rop = |op|;
void mpz_cdiv_q(mpz_t q, mpz_t n, mpz_t d);              // q = n / d;
void mpz_cdiv_r(mpz_t r, mpz_t n, mpz_t d);              // r = n % d;
void mpz_cdiv_qr(mpz_t q, mpz_t r, mpz_t n, mpz_t d);    // q = n / d, r = n % d;

还可以大整数和普通类型混合运算:

void mpz_add_ui(mpz_t rop, mpz_t x, unsigned long y);  // x+y ⇒ rop
void mpz_sub_ui(mpz_t rop, mpz_t x, unsigned long y);  // x-y ⇒ rop
void mpz_ui_sub(mpz_t rop, unsigned long x, mpz_t y);  // x-y ⇒ rop // 留意,减法有两个变体。
void mpz_mul_ui(mpz_t rop, mpz_t x, unsigned long y);  // x*y ⇒ rop

gmp库支持计算函数中变量重复,例如 mpz_mul(C,C,C); 就会将C平方的值赋给C,并不会报错。

6. 交换两个大整数:

void mpz_swap(mpz_t A, mpz_t B);

7. 幂函数:

//  大整数的整型次方, rop = base ^ exp;
void mpz_pow_ui(mpz_t rop, const mpz_t base, unsigned long exp);

//  整型的整型次方,   rop = base ^ exp;
void mpz_ui_pow_ui(mpz_t rop, unsigned long base, unsigned long exp);

//  大整数的大整数次方模大整数,  rop = (base ^ exp) % m;
void mpz_powm(mpz_t rop, const mpz_t base, const mpz_t exp, const mpz_t m);

//  大整数的整型次方模大整数,    rop = (base ^ exp) % m;
void mpz_powm_ui(mpz_t rop, const mpz_t base, unsigned long exp, const mpz_t m);

//  可能因为大整数的大整数次方太大了,所以没有mpz_pow()函数,只有取模版的。

8. gmp中对变量的操作是使用指针,因此不要对变量进行copy!

GMP默认使用malloc系列函数进行内存分配。

例如我们想写一个函数,返回值不能设为mpz_t,也不用取地址,直接用mpz_t定义形参即可。

void add(mpz_t C,mpz_A,mpz_B)   //A = B+C;
{
    mpz_add(C,A,B);
    return ;
}

int main() {
	mpz_t A,B,C;
	mpz_inits(A,B,C,NULL);
	mpz_set_ui(A,114514);
	mpz_set_ui(B,1919810);
	add(C,A,B);
	return 0;
}

不定期更新qwq ————2023.03.20

posted @ 2023-05-14 17:41  maple276  阅读(1473)  评论(1编辑  收藏  举报