GMP库使用

Aki 发布于 2023-07-30 495 次阅读


GMP(GNU多精度数学库)是一个功能强大的开源数学库,用于高精度计算和操作任意精度的整数、有理数和浮点数。它提供了一组丰富的函数和数据类型,使得处理大数和高精度计算变得容易和高效。

以下是 GMP 库的一些主要特点和功能:

  • 任意精度计算:GMP 允许处理任意精度的整数、有理数和浮点数,不受标准整数和浮点数类型的限制。通过 GMP,可以进行准确度高达数百万位的计算。
  • 高效的算法:GMP 库通过使用高效的算法和数据结构来实现快速的大数计算。它使用了各种优化技术,如手动调整乘法算法、快速离散傅立叶变换(FFT)等。
  • 丰富的功能:GMP 提供了一系列的数学函数和操作,包括基本的算术运算、位操作、比较运算、转换函数、随机数生成、高级数论运算(如最大公约数、质因数分解、素数测试)等。
  • 灵活的数据类型:GMP 引入了自己的数据类型来表示大整数(mpz_t)、有理数(mpq_t)和浮点数(mpf_t)。这些数据类型可以动态分配和调整内存大小,以适应任意精度的计算需求。
  • 跨平台支持:GMP 是一个跨平台的库,可以在各种操作系统上使用,包括 Windows、Linux、Mac 等。它使用纯 C 语言编写,因此可以与各种编程语言进行集成。
  • 广泛应用:GMP 库被广泛应用于科学计算、密码学、密码分析、符号计算、编译器优化等领域。它提供了很多基础工具和函数,用于构建其他高级数学库和应用程序。

GMP 是一个功能强大且高度优化的开源数学库,用于高精度计算和操作任意精度的数值。它提供了丰富的功能和灵活的数据类型,适用于各种数学操作和应用场景。

一些常用操作、

  • mpz_tmpz_t 是 GMP 中表示任意精度整数的数据类型。它通过动态分配的内存来存储大整数,并提供了各种函数和操作,用于进行整数的基本运算、位操作、比较运算等。
  • mpq_tmpq_t 是 GMP 中表示任意精度有理数的数据类型。它由两个 mpz_t 对象组成,一个表示分子,一个表示分母。mpq_t 类型提供了函数和操作,用于进行有理数的基本运算、转换、比较等。
  • mpf_tmpf_t 是 GMP 中表示任意精度浮点数的数据类型。它可以用来进行高精度的浮点数计算,支持加法、减法、乘法、除法、指数、对数运算等。mpf_t 类型具有用户可选的精度,可以通过设置小数位数来控制计算精度。
  • 上述类型的数据的位数都是动态扩展的!!!

mpz_t类型基本操作!!!

#include<iostream>
#include<gmp.h>
using namespace std;

int main()
{

        //定义
        mpz_t z1,z2,z3;         //创建没有位数限制的高精度有符号整数


        //默认初始化
        mpz_init(z1);           //初始化为0,每一个mpz_t类型数据使用前都需要初始化!
        mpz_init(z2);           //初始化为0,每一个mpz_t类型数据使用前都需要初始化!
        mpz_init(z3);           //初始化为0,每一个mpz_t类型数据使用前都需要初始化!


        //数字初始化
        mpz_init_set_si(z1,-100);    //使用一个 signed int 有符号数来初始化,可以是负数和正数!
        mpz_init_set_ui(z1,100);     //使用一个 unsigned int 无符号数来初始化,只能为正数!


        //mpz_t类型初始化
        mpz_init_set(z2,z1);         //将z1的值赋值给z2


        //字符串初始化
        char num[] = "114514";          //数字字符串,要保证只有数字字符!!!
        mpz_init_set_str(z1,num,10);    //使用一个数字字符串来初始化,需要指定进制


        //使用字符串赋值
        mpz_set_str(z1,"114514",10);


        //使用数字赋值
        mpz_set_si(z1,-100);    //使用一个 signed int 有符号数来赋值,可以是负数和正数!
        mpz_set_ui(z1,100);     //使用一个 unsigned int 无符号数来赋值,只能为正数!


        //使用mpz_t类型来赋值
        mpz_set(z1,z2);


        //获取字符串
        char buffer[512];
        mpz_get_str(buffer,10,z1);  //转换为字符串类型,需要指定缓冲区(缓冲区大小要足够!)和进制;


        //比较运算
        mpz_cmp(z1,z2);             //比较两个mpz_t类型数据的大小;z1 = z2返回0;z1 > z2 返回大于0;z1 < z2 返回小于0
        mpz_cmp_si(z1,100);         //将mpz_t类型数据与 signed int 类型数据比较,返回值和上述相同


        //加法运算
        mpz_add(z3,z1,z2);          //mpz_t类型的加法,z3 = z1 + z2
        mpz_add_ui(z3,z1,10);       //mpz_t类型的加法,z3 = z1 + 10; 注意10是ui类型数据,unsigned int无符号整数!!!
        //gmp库没有提供mpz_add_si类型的函数!!!!


        //减法运算
        mpz_sub(z3,z1,z2);          //mpz_t类型的减法,z3 = z1 - z2;
        mpz_sub_ui(z3,z1,10);       //z3 = z1 - 10;


        //乘法运算
        mpz_mul(z3,z1,z2);          //z3 = z1 * z2
        mpz_mul_ui(z3,z1,10);       //z3 = z1 * 10


        //除法运算
        mpz_div(z3,z1,z2);         //z3 = z1 / z2
        mpz_div_ui(z3,z1,10);      //z3 = z1 / 10


        //幂运算
        mpz_pow_ui(z3,z1,10);      //z3 = z1 ** 10
        mpz_powm(z3,z1,z2,z2);     //z3 = z1 ** z2 mod z2


        //取余运算
        mpz_mod(z3,z1,z2);        //z3 = z1 mod z2
        mpz_mod_ui(z3,z1,10);     //z3 = z1 mod 10;


        //获取质数
        mpz_nextprime(z1,z1);    //获取大于z1的下一个质数并赋值给z1


        //验证是不是质数
        mpz_probab_prime_p(z1,15);  //返回值为0,1,2;当返回值为2时是素数的概率极高,接近百分白;返回值为1时给定整数可能是素数,但可能存在较小的错误概率;返回值为0时给定整数不是素数;15是测试的次数,通常使用15次的测试已经可以给出较高的准确性;


        //获取随时间变化的随机数
        //(1)设置默认随机状态为跟着时间改变,也就是引入时间随机数种子
        gmp_randstate_t state;
        gmp_randinit_default(state);
        gmp_randseed_ui(state,time(NULL));

        //(2)生成指定位数的随机数,例如1024位
        mpz_urandomb(z1,state,1024);


        //计算两个整数的最大公约数
        mpz_gcd(z3,z1,z2);         //计算z1和z2的最大公约数,结果保存至z3中


        //计算最小公倍数,公式:最小公倍数 = (num1 * num2) / 最小公约数
        mpz_set_ui(z1,18);
        mpz_set_ui(z2,6);
        mpz_t z4,z5;
        mpz_init(z4);
        mpz_init(z5);
        mpz_gcd(z3,z1,z2);   //z3是最小公约数
        mpz_mul(z4,z1,z2);   //z4 = z1 * z2;计算乘积!
        mpz_div(z5,z4,z3);   //z5 = z4 / z3;z5是最小公倍数!


        //标准输出
        gmp_printf("%Zd\n",z5); 


        //通过输入设置一个mpz_t类型数据的大小
        char num_buffer[512];
        cin >> num_buffer;
        mpz_t z6;
        mpz_init_set_str(z6,num_buffer,10);


        //按位与运算
        mpz_and(z1,z2,z3);     //z1 = z2 & z3


        //按位或运算
        mpz_ior(z1,z2,z3);     //z1 = z2 | z3


        //按位异或运算
        mpz_xor(z1,z2,z3);     //z1 = z2 ^ z3


        //按位取反操作
        mpz_com(z1,z1);        //z1 = ^z1


        //左移位运算
        mpz_mul_2exp(z1,z1,2);  //z1 = z1 << 2;


        //右移位运算
        mpz_tdiv_q_2exp(z1,z1,2); //z1 = z1 >> 2;



        //清理
        mpz_clear(z1);         // 清理资源
        mpz_clear(z2);         // 清理资源
        mpz_clear(z3);         // 清理资源
        mpz_clear(z4);         // 清理资源
        mpz_clear(z5);         // 清理资源
        mpz_clear(z6);         // 清理资源



        return 0;
}