嗯刚刚终于搞定了大数运算真是让我异常感动于是我又选择了来记录一下这次历程。
本来是想用C++实现一个MMM来测试verilog写出来的对不对的,刚开始觉得很容易啊不就把计算过程一写就好了,然而写到32位的时候求n'的时候需要用到r * r-1就发现溢出了……然后就不得不寻求大数运算的方法。
然而由于我太懒了不想自己动手写big integer,自己这方面的知识又很匮乏不知道有没有什么现成的工具,然后就搜了一下发现了GNU的GMP库然后就准备试一下了。
然而感觉网上很少配置GMP库的相关教程?或者也可能是我的打开方式不对,总之谷歌和度娘都搜不到太多有用的,只搜到了唯一一篇windows下配置GMP库的博客,还好良心博主的方法肥肠好用,终于不像之前装软件那样痛苦不堪。以下也就再写一下GMP库的安装方法,和GMP的C++ interface的使用(就用我的MMM代码啦)吧。
-------------------------------------------------------------------------------------以上是废话以下是正文的分割线------------------------------------------------------------------------------------------------
一、GMP库在Windows下的配置
参考文章:http://blog.csdn.net/u012629110/article/details/51220727
Emmm这篇文章里面已经讲得非常详细啦我就懒得再写一遍了(明明刚刚还想重新写的然而太懒了orz),配置过程中没出现什么大问题,就是本来昨天下午第一次装的时候在最后一步安装mingw-base的时候一直卡在一个地方好久,后来蹦出来一个错误提示我也没仔细看,然后整个Installer就卡掉了我就直接强行关掉了。今天重新打开installer安装就非常顺畅,所以有问题就先关了过一会儿再重新来一遍吧hhh
二、GMP库的日常使用方法
首先贴出GMP官方文档:https://gmplib.org/gmp-man-6.1.0.pdf
然后我就说一下最简单粗暴的理解好了可能不太对但是能应付一下日常使用:
头文件需要加上:#include
数据类型:mpz_t a;
在声明变量以后需要先初始化:mpz_init(a);
给变量赋值:mpz_set_str(a, "4294967296", 10); //a是要被赋值的变量,中间那串数字是值,最后是基数
两个mpz_t之间的加减乘除模:mpz_mul(result, a, b); //这个是乘法,a乘b的结果存在result里,其他运算把mul改成对应的add(加)、sub(减)、div(除)、mod(模)
mpz_t和普通unsigned int之间的运算:mpz_mul_ui(result, a, 1); //加减除模同上
输出大数:mp_printf("%Zd\n", a); //大数的格式化标志是%Zd
由于没有研究出来怎么用VS配置gmp于是就用了上面提到的那篇博客的直接命令行编译执行方法:
gcc test.cpp -lgmp -lm -o test
Emmm目前我就用了这些,就是最基本的四则运算吧,具体还是参考官方文档啦。但是这个感觉实在是太麻烦和我之前写的C++直接用加减乘除模符号的版本需要改动的地方太多了,然后我就翻了一下官方文档找了一下C++ interface,然后就发现了另一种超级简单方便的方法。
头文件需要加上:#include
数据类型:mpz_class a;
然后可以直接方便地使用C++的赋值语句进行赋值:a = "4294967296"; //注意需要把它当字符串
然后好像其他就跟C++完全一样了就是把平时用的int啦long啦什么的改成mpz_class就好啦真是简单快捷!
三、以下是我的MMM的代码
#include
#include
using namespace std;
//command line: g++ test_interface.cpp -lgmpxx -lgmp -o test_interface
mpz_class extended_euclid(mpz_class a, mpz_class n)
{
mpz_class t, t_next;
mpz_class r, r_next;
t = 0;
t_next = 1;
r = n;
r_next = a;
while (r_next != 0)
{
mpz_class quotient = r / r_next;
mpz_class t_next_temp = t_next;
mpz_class r_next_temp = r_next;
t_next = t - quotient * t_next;
r_next = r - quotient * r_next;
t = t_next_temp;
r = r_next_temp;
}
if (r > 1)
return 0;
if (t < 0)
t += n;
return t;
}
mpz_class MMM(mpz_class a, mpz_class b, mpz_class r, mpz_class n)
{
mpz_class a_mont = a * r % n;
mpz_class b_mont = b * r % n;
mpz_class t = a_mont * b_mont % r;
mpz_class r_inverse = extended_euclid(r % n, n);
//cout << "r: " << r << " r_inverse: " << r_inverse << endl;
mpz_class n_prime = (r * r_inverse - 1) / n;
//cout << "n: " << n << "n_prime: " << n_prime << endl;
mpz_class m = t * n_prime % r;
mpz_class u = (a_mont * b_mont + m * n) / r;
if (u >= n)
u = u -n;
return (u * r_inverse % n);
}
int main ()
{
mpz_class a, b, r, n;
a = "305419896";
b = "2271560481";
r = "4294967296";
n = "4292870399";
// 8bit: a = 182, b = 90, r = 256, n = 255; result = 60
// 16bit: a = 4660, b = 17185, r = 65536, n = 65535; result = 63865
// 32bit: a = 305419896, b = 2271560481, r = 4294967296, r-1 = 3234391457, n = 4292870399, n_prime = 3235971329, result = 4290335667
cout << a << " * " << b << " mod " << n << " = " << MMM(a, b, r, n) << endl;
return 0;
}
小白一个欢迎大家指出错误啥的hhh
滚去复习database了明天还要midterm嘤嘤嘤。