GMP库使用以及java中的BigInteger和BigDecimal

这篇具有很好参考价值的文章主要介绍了GMP库使用以及java中的BigInteger和BigDecimal。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、GMP介绍和安装

GMP library全称是GNU Multiple Precision Arithmetic Library,即GNU高精度算术运算库。在网络安全技术领域中各种加密算法的软件实现始终有一个共同话题是如何在普通的PC机上实现大数运算。普通的PC机内部字长最多时32位或64位,但各种加密算法中为了达到一定安全强度,都要求在128位、512位或1024位字长下进行加减乘除等数学运算,这叫做“大数运算”。

在此前提下,如何在普通的PC机上高效快速的实现大数运算成为加密算法在普通PC机上软件实现的重要问题。如python等语言都内建大数计算机制,但C/C++语言既没有内建大数运算机制,也没有对应的标准库实现。

GMP大数库是GUN项目的一部分,诞生于1991年,作为一个任意精度的大整数运算库,它包含了任意精度的整数、浮点数的各种基础运算操作。它是一个C语言库,并提供了C++的包装类,主要应用于密码学应用和研究、互联网安全应用、代数系统、计算代数研究等。

GMP库运行速度非常快,官网上称自己是地球上最快的大数库,但GMP只提供了基础数学运算,并没有提供密码学的相关运算。

1、在Mac上安装

 到官网下载相应的包。

# Mac下方便解压,直接下载 gmp-6.2.0.tar.xz 版本
# 解压 
$ tar -xvf gmp-6.2.0.tar

# 编译
$ cd gmp-6.2.0
$ ./configure --enable-cxx
$ make -j4  # 4 核心编译速度更快 也可以直接 make

# 对编译进行自测
$ make check

# 安装 默认路径为/usr/local
$ sudo make install

注:由于GMP是C语言库,但也提供了C++的包装类,在编译时,如果要增加C++支持,./configure时加上--enable-cxx参数,这样才能使用c++库gmpxx.h

2、使用库

链接到 libgmp 库,使用选项 -lgmp:

gcc myprogram.c -lgmp

c++函数在 libgmpxx 库中,因此需要额外的编译选项:

g++ mycxxprog.cc -lgmpxx -lgmp

3、示例

1)整型运算:

testgmp.cpp:

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

int main()
{
    mpz_t a,b,c,d;  // define
    mpz_init(a);  // initialize
    mpz_init(b);
    mpz_init(c);
    mpz_init(d);
    gmp_scanf("%Zd%Zd",a,b);  // input
    mpz_add(c,a,b);  // compute c = a + b
    gmp_printf("%Zd\n",c);  // output
    mpz_mul(d,a,b);  // compute d = a * b
    gmp_printf("%Zd\n",d);  // output
    mpz_clear(a);  // clear memory
    mpz_clear(b);
    mpz_clear(c);
    mpz_clear(d);
    return 0;
}

编译、运行

# 编译
$ g++ -o testgmp.out testgmp.cpp -lgmpxx -lgmp

# 运行
$ ./testgmp.out
324327543564685049860389045809768327483265873264578346593489
100000000000000000000000000000000000000000000000000000000001

 输出:

424327543564685049860389045809768327483265873264578346593490
3243275435646850498603890458097683274832658732645783465934922432754356468504986038904580976832748326587326457

2)浮点型运算:

testgmp2.cpp

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

int main()
{
    mpf_set_default_prec(64); // 默认精度,即小数点后精确多少位
    mpf_t a,b,c,d;  // define

    mpf_init(a);  // initialize
    mpf_init(b);
    mpf_init(c);
    mpf_init(d);

    gmp_scanf("%Ff%Ff",a,b);  // input
    mpf_add(c,a,b);  // compute c = a + b
    gmp_printf("%Ff\n",c);  // output
    mpf_mul(d,a,b);  // compute d = a * b
    gmp_printf("%Ff\n",d);  // output
    mpf_clear(a);  // clear memory
    mpf_clear(b);
    mpf_clear(c);
    mpf_clear(d);
    return 0;
}

 编译、运行

$ g++ -o testgmp2.out testgmp2.cpp -lgmpxx -lgmp
$ ./testgmp2.out
9876543.123456
123456.987654

输出

10000000.111110
1219328262456.705990

 4、GMP库介绍

  • 在线文档:Top (GNU MP 6.2.1)
  • 官方手册:https://gmplib.org/gmp-man-6.2.1.pdf

4.1)数据类型:

  • mpz_t(整数)    mpz_开头
  • mpq_t(有理数)    mpq_开头
  • mpf_t(浮点数)    mpf_开头

4.2)使用步骤:(以浮点型为例)

1)声明变量:

mpf_t fnum;

2)初始化变量:

mpf_init(fnum); //或mpf_init(fnum,20),此函数指针对类型mpf_t有效

3)变量赋值:

mpf_set_str(fnum,"1.23",10);    //以10为进制数,表示浮点数的字符串来赋值fnum

//mpf_set_str的原型
int mpf_init_set_str (mpf_ptr, const char *, int);
其中三个参数表示为多精度浮点数变量、字符串、进制。

4)变量计算:

mpf_mul(fnum,fnum,tmp);    //fnum和tmp都是mpf_t类型的变量

5)释放变量:

mpf_clear(fnum);    

 4.3)常用方法:

  • 加法:void mpz_add(mpz_t rop, mpz_t op1, mpz_t op2);  //rop = op1 + op2
  • 减法:void mpz_sub(mpz_t rop, mpz_t op1, mpz_t op2);  //rop = op1 - op2
  • 乘法:void mpz_mul(mpz_t rop, mpz_t op1, mpz_t op2); //rop = op1 * op2
  • 除法:void mpz_cdiv_q (mpz_t q, mpz_t n, mpz_t d);  //q = n/d,这个有很多种类型,具体的看使用手册
  • 幂运算:void mpz_pow_ui (mpz_t rop, mpz_t base, unsigned long int exp);  //rop = base^exp
  • 开方:void mpz_sqrt (mpz_t rop, mpz_t op); //rop = op开方的向下取整

5、应用:(RSA加密)

#include <iostream>
#include <gmpxx.h>
#include <cstdlib>

using namespace std;

mpz_class randbits(int bits) // base = 2
{
    gmp_randclass a(gmp_randinit_default);
    a.seed(rand());
    mpz_class l(bits);
    return a.get_z_bits(l);
}

inline mpz_class randprime(int bits)
{
    mpz_class a = randbits(bits);
    mpz_class ret;
    mpz_nextprime(ret.get_mpz_t(), a.get_mpz_t());
    return ret;
}

void setKey(mpz_class &n, mpz_class &e, mpz_class &d, const int nbits, int ebits = 16)
{
    if (nbits / 2 <= ebits)
    {
        ebits = nbits / 2;
    }
    mpz_class p = randprime(nbits / 2); //随机取p
    mpz_class q = randprime(nbits / 2); //随机取q
    n = q * p;                          //计算n=p*q
    mpz_class fn = (p - 1) * (q - 1);   //计算欧拉数
    mpz_class gcd;
    do
    {
        e = randprime(ebits);           //随机取e
        mpz_gcd(gcd.get_mpz_t(), e.get_mpz_t(), fn.get_mpz_t());       //判断gcd(e,fn)=1是否成立
    } while (gcd != 1);
    //mpz_gcdext(g, s, t, a, b): g = as + bt
    mpz_gcdext(p.get_mpz_t(), d.get_mpz_t(), q.get_mpz_t(), e.get_mpz_t(), fn.get_mpz_t()); //计算d=e^{-1} mod fn
}

inline mpz_class encrypt(const mpz_class &m, const mpz_class &e, const mpz_class &n)
{
    mpz_class ret;
    mpz_powm(ret.get_mpz_t(), m.get_mpz_t(), e.get_mpz_t(), n.get_mpz_t()); //ret=m^e mod n
    return ret;
}

inline mpz_class decrypt(const mpz_class &c, const mpz_class &d, const mpz_class &n)
{
    return encrypt(c, d, n);    //m=c^d mod n
}

int main()
{
    int nbits;
    cout << "输入大数比特数:";
    cin >> nbits;
    mpz_class n, e, d;
    setKey(n, e, d, nbits);         //密钥生成
    cout << "公钥:(e=" << e.get_str() << ", n=" << n.get_str() << ")" << endl;
    cout << "私钥:(d=" << d.get_str() << ", n=" << n.get_str() << ")" << endl;

    cout << "输入加密数据:";
    string s;
    cin >> s;

    mpz_class m(s);
    mpz_class c;
    c = encrypt(m, e, n);       //加密
    cout << "加密后:" << c.get_str() << endl;
    c = decrypt(c, d, n);       //解密
    cout << "解密后:" << c.get_str() << endl;
    if (c == m)
        cout << "加/解密成功!" << endl
             << endl;
    else
        cout << "加/解密失败!" << endl
             << endl;

    string q;
    cout << "是否继续(Y/N):";
    cin >> q;
    if (q == "y" || q == "Y")
        main();
    return 0;
}

二、java中的BigInteger和BigDecimal

1、BigInteger:

在Java中,由CPU原生提供的整型最大范围是64位long型整数。使用long型整数可以直接通过CPU指令进行计算,速度非常快。

如果我们使用的整数范围超过了long型怎么办?这个时候,就只能用软件来模拟一个大整数。java.math.BigInteger就是用来表示任意大小的整数。BigInteger内部用一个int[]数组来模拟一个非常大的整数。和long型整数运算比,BigInteger不会有范围限制,但缺点是速度比较慢。

private static void test() {
	BigInteger a = new BigInteger("324327543564685049860389045809768327483265873264578346593489");
	BigInteger b = new BigInteger("100000000000000000000000000000000000000000000000000000000001");
	
	BigInteger c = a.add(b);
	BigInteger d = a.multiply(b);
	System.out.println(c.toString());//424327543564685049860389045809768327483265873264578346593490
	System.out.println(d.toString());//32432754356468504986038904580976832748326587326457834659349224327543564685049860389045809768327483265873264578346593489
}

2、BigDecimal:

和BigInteger类似,BigDecimal可以表示一个任意大小且精度完全准确的浮点数。如果查看BigDecimal的源码,可以发现,实际上一个BigDecimal是通过一个BigInteger和一个scale来表示的,即BigInteger表示一个完整的整数,而scale表示小数位数。

1)除法运算:

对BigDecimal做加、减、乘时,精度不会丢失,但是做除法时,存在无法除尽的情况,这时,就必须指定精度以及如何进行截断:

BigDecimal d1 = new BigDecimal("123.456");
BigDecimal d2 = new BigDecimal("23.456789");
BigDecimal d3 = d1.divide(d2, 10, RoundingMode.HALF_UP); // 保留10位小数并四舍五入
BigDecimal d4 = d1.divide(d2); // 报错:ArithmeticException,因为除不尽

2)比较:

在比较两个BigDecimal的值是否相等时,要特别注意,使用equals()方法不但要求两个BigDecimal的值相等,还要求它们的scale()相等:

BigDecimal d1 = new BigDecimal("123.456");
BigDecimal d2 = new BigDecimal("123.45600");
System.out.println(d1.equals(d2)); // false,因为scale不同
System.out.println(d1.equals(d2.stripTrailingZeros())); // true,因为d2去除尾部0后scale变为2
System.out.println(d1.compareTo(d2)); // 0

所以,必须使用compareTo()方法来比较,它根据两个值的大小分别返回负数、正数和0,分别表示小于、大于和等于。

3)求余数

BigDecimal n = new BigDecimal("12.345");
BigDecimal m = new BigDecimal("0.12");
BigDecimal[] dr = n.divideAndRemainder(m);
System.out.println(dr[0]); // 102
System.out.println(dr[1]); // 0.105

 调用divideAndRemainder()方法时,返回的数组包含两个BigDecimal,分别是商和余数,其中商总是整数,余数不会大于除数。我们可以利用这个方法判断两个BigDecimal是否是整数倍数:

BigDecimal n = new BigDecimal("12.75");
BigDecimal m = new BigDecimal("0.15");
BigDecimal[] dr = n.divideAndRemainder(m);
if (dr[1].signum() == 0) {
    // n是m的整数倍
}



https://www.cnblogs.com/pam-sh/p/17368429.html

C/C++ gmp库之浮点数实例 | 织梦先生文章来源地址https://www.toymoban.com/news/detail-474020.html

到了这里,关于GMP库使用以及java中的BigInteger和BigDecimal的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MAC中的JAVA安装以及环境配置

    MAC中的JAVA安装以及环境配置 Mac OS安装JDK以及配置环境0基础适宜 目录: 一、JDK的下载以及安装 二、安装路径以及环境配置 三、使配置生效 首先是到Oracle官网下载适合的JDK安装包,可以根据需要来选择对应的安装包 官网下载链接: Java Downloads | Oracle 点击上方链接即可跳转到

    2024年02月08日
    浏览(37)
  • 日常BUG——Java使用Bigdecimal类型报错

    😜 作           者 :是江迪呀 ✒️ 本文 : 日常BUG 、 BUG 、 问题分析 ☀️ 每日   一言 : 存在错误说明你在进步! 直接上代码: 报错内容: 原来JAVA中如果用 BigDecimal 做除法的时候一定要在divide方法中传递第二个参数,定义精确到小数点后几位,否则在不整除

    2024年02月13日
    浏览(34)
  • Linux 中的以太网管理,以及udhcpc介绍和使用步骤

    在Linux中, udhcpc 是一个用于动态获取IP地址的工具,通常用于DHCP(Dynamic Host Configuration Protocol)网络配置。它是BusyBox工具集中的一部分,用于从DHCP服务器获取IP地址、网关、DNS服务器等网络配置信息。 以下是 udhcpc 的基本介绍和使用流程: 1. 安装 udhcpc : udhcpc 通常是与Bus

    2024年04月22日
    浏览(21)
  • java BigDecimal使用(小数点,字符串等转换)

    Java中提供了操作大数字(超过 16位 有效位)的类, 即 java.math.BigInteger 类和 java.math.BigDecimal 类,用于高精度计算。 float和Double只能用来做科学计算、工程计算等;在商业计算中,对数字精度要求较高(例如货币值),必须使用 BigInteger 类和 BigDecimal 类,它支持任何精度的定点数,

    2024年02月14日
    浏览(30)
  • Java开发手册中为什么禁止使用BigDecimal的equals方法做等值比较已经为什么禁止使用double直接构造BigDecimal

    阿里Java开发手册嵩山版中明确指出: 1、BigDecimal的等值比较应使用compareTo()方法,而不是equals()方法 equals()方法会比较值和精度(1.0与1.00返回结果为false),而compareTo()则会忽略精度 2、禁止使用构造方法BigDecimal(double)的方式把double值转换为BigDecimal对象 BigDecimal(double)存在精度损

    2024年02月07日
    浏览(43)
  • 66. 加一(Java):BigInteger

    给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 你可以假设除了整数 0 之外,这个整数不会以零开头。 digits = [4,3,2,1] [4,3,2,2] 解释:输入数组表示数字 4321。 BigInteger 是Java中的一

    2024年01月25日
    浏览(26)
  • ElasticSearch之IK分词器安装以及使用介绍

    elasticsearch 默认的内置分词器对中文的分词效果可能并不理想,因为它们主要是针对英文等拉丁语系的文本设计的。如果要在中文文本上获得更好的分词效果,我们可以考虑使用中文专用的分词器。 IK 分词器是一个开源的中文分词器插件,特别为 Elasticsearch 设计和优化。它在

    2024年02月13日
    浏览(31)
  • 阿里云免费SSL证书的简单介绍以及安装使用

    qquad 阿里云SSL证书服务提供免费版SSL证书(即免费证书)和付费版SSL证书(即付费证书)。免费证书主要以公益目的提供给阿里云用户使用,便于个人或企业用户在网站建设之初或业务需要使用HTTPS通信时进行测试。 qquad 免费证书一般仅用于个人网站或测试使用,不建议业

    2024年02月06日
    浏览(53)
  • JSON 基本语法以及在Java 中的使用

    JSON(JavaScript Object Notation)是一种轻量级的数据交互格式。它去除了所有 JavaScript 执行代码,只保留 JavaScript 的对象格式。 它基于 ECMAScript (欧洲计算机协会制定的 js 规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。 JSON适合表示层次结构,JSON采用键

    2024年01月23日
    浏览(35)
  • snmp trap 与snmp相关介绍、安装、命令以及Trap的发送与接收java实现

    1.1、什么是Snmp SNMP是英文\\\"Simple Network Management Protocol\\\"的缩写,中文意思是\\\"简单网络管理协议\\\"。SNMP是一种简单网络管理协议,它属于TCP/IP五层协议中的应用层协议,用于网络管理的协议。SNMP主要用于网络设备的管理。由于SNMP协议简单可靠 ,受到了众多厂商的欢迎,成为了目

    2024年02月02日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包