BUG 记录:移位运算与扩展欧几里得算法
BUG 记录:移位运算与扩展欧几里得算法
起因
上个月就开始打算用C++写一个ECC的轮子(为什么?折磨自己呗!),奈何自己水平有点差,拖到现在才算写完底层的大数运算。在实现欧几里得算法的时候,我开始纠结了...
欧几里得算法的两种实现
耳熟能详的实现方案
这个实现只要了解过欧几里得算法的同学都很清楚,我把维基百科上的代码粘贴到这里,最开始我也是按照这样的方式写出来的代码,没过几个测试,bug就出来了。
def ext_euclid(a, b):
old_s,s=1,0
old_t,t=0,1
old_r,r=a,b
if b == 0:
return 1, 0, a
else:
while(r!=0):
q=old_r//r
old_r,r=r,old_r-q*r
old_s,s=s,old_s-q*s
old_t,t=t,old_t-q*t
return old_s, old_t, old_r
乍一看,这个实现真是天衣无缝,毫无破绽,但是要是实现大数运算的时候,如果要是这么想的话,就太naive了。
矩阵计算欧几里得算法
原理我就不抄了,刚学会的,链接在此
https://www.wikiwand.com/zh/輾轉相除法#/矩阵法
这两个方法看起来其实是等价的,第二个方法无非就是拿矩阵表示了一下,有同学会问了,这能有啥区别?
书本上的方法的问题所在
其实最开始的时候,我在我的大数系统实现的时候,我就意识到了有可能会有这样的问题:
注意上面代码中循环中的操作,减法?乘法?
q*s
和q*t
其实在a
和b
很大的时候有溢出的风险。
注意到这个问题之后,我用python实现了一下,果然!这个操作会溢出!又用python实现了一个matrix,这回没有这个问题。(我把代码放在最后)
结论
仔细看看这两种方法,第二种方法其实是一种推迟了减法的做法。矩阵上的元素始终在增长,且不会超过a
和b
的最高位,代价就是多了两个需要存储的元素。
移位运算坑死我这样的小白
我修改了上面的代码,又测试了一下,还是不对,我慌了,最终使用中间量对比大法,一步一步去对比,人肉检查,我发现了问题所在。
实现gcd免不了带余除法(欧几里得除法)的操作,对于除法,我本来还想优化优化,但是奈何水平有点捉急,最后写了个textbook division(列等式减法那种),里面的当然有移位运算了,就是这个移位运算搞我。
void NB::rshift(int bitnum){
/* calculate block num and remain num */
int blocknum = bitnum/64;
int remainnum = bitnum%64;
WORD tmp1 = 0;
WORD tmp2 = 0;
/* first step , move the blocknum */
for(int i=0;i<MAX_number_word;i++){
if(i-blocknum>=0){
this->val[i-blocknum] = this->val[i];
}
}
for(int i=MAX_number_word-1;i>=MAX_number_word-blocknum;i--){
this->val[i] = 0;
}
/* second step , move the remainnum */
for(int i=MAX_number_word-1;i>=0;i--){
tmp1 = this->val[i]<<(WORDSIZE-remainnum);
this->val[i] = this->val[i]>>remainnum;
this->val[i] += tmp2;
tmp2 = tmp1;
}
}
毫无破绽的代码(划掉,并不是)。注意第二步写移位运算的时候有一句:
tmp1 = this->val[i]<<(WORDSIZE-remainnum);
当remainnumd=0
,就会出现移位WORDSIZE
的情况,聪明的小伙伴都知道,这种情况在C++标准里是没有定义的,即
移位运算的右操作符的大小应该大于等于0小于左操作符的最大位数,其余情况是未定义的。
所以不太聪明但是有效的做法->
/* second step , move the remainnum */
for(int i=MAX_number_word-1;i>=0;i--){
if(remainnum==0){
tmp1 = 0;
}else{
tmp1 = this->val[i]<<(WORDSIZE-remainnum);
}
this->val[i] = this->val[i]>>remainnum;
this->val[i] += tmp2;
tmp2 = tmp1;
}
结束
表达了对眼前有码,心中无码的境界的期待。
BUG 记录:移位运算与扩展欧几里得算法的更多相关文章
- ****ural 1141. RSA Attack(RSA加密,扩展欧几里得算法)
1141. RSA Attack Time limit: 1.0 secondMemory limit: 64 MB The RSA problem is the following: given a ...
- 『扩展欧几里得算法 Extended Euclid』
Euclid算法(gcd) 在学习扩展欧几里得算法之前,当然要复习一下欧几里得算法啦. 众所周知,欧几里得算法又称gcd算法,辗转相除法,可以在\(O(log_2b)\)时间内求解\((a,b)\)( ...
- 扩展欧几里得算法详解(exgcd)
一.前言 本博客适合已经学会欧几里得算法的人食用~~~ 二.扩展欧几里得算法 为了更好的理解扩展欧几里得算法,首先你要知道一个叫做贝祖定理的玄学定理: 即如果a.b是整数,那么一定存在整数x.y使得$ ...
- 初等数论-Base-2(扩展欧几里得算法,同余,线性同余方程,(附:裴蜀定理的证明))
我们接着上面的欧几里得算法说 扩展欧几里得算法 扩展欧几里德算法是用来在已知a, b求解一组x,y,使它们满足贝祖等式\(^①\): ax+by = gcd(a, b) =d(解一定存在,根据数论中的 ...
- 扩展欧几里得算法(extgcd)
相信大家对欧几里得算法,即辗转相除法不陌生吧. 代码如下: int gcd(int a, int b){ return !b ? gcd(b, a % b) : a; } 而扩展欧几里得算法,顾名思义 ...
- noip知识点总结之--欧几里得算法和扩展欧几里得算法
一.欧几里得算法 名字非常高大上的不一定难,比如欧几里得算法...其实就是求两个正整数a, b的最大公约数(即gcd),亦称辗转相除法 需要先知道一个定理: gcd(a, b) = gcd(b, a ...
- 欧几里得算法与扩展欧几里得算法_C++
先感谢参考文献:http://www.cnblogs.com/frog112111/archive/2012/08/19/2646012.html 注:以下讨论的数均为整数 一.欧几里得算法(重点是证 ...
- vijos1009:扩展欧几里得算法
1009:数论 扩展欧几里得算法 其实自己对扩展欧几里得算法一直很不熟悉...应该是因为之前不太理解的缘故吧这次再次思考,回看了某位大神的推导以及某位大神的模板应该算是有所领悟了 首先根据题意:L1= ...
- 浅谈扩展欧几里得算法(exgcd)
在讲解扩展欧几里得之前我们先回顾下辗转相除法: \(gcd(a,b)=gcd(b,a\%b)\)当a%b==0的时候b即为所求最大公约数 好了切入正题: 简单地来说exgcd函数求解的是\(ax+by ...
随机推荐
- 『学了就忘』Linux文件系统管理 — 66、通过图形界面进行LVM分区
目录 1.选择自定义分区 2.分配boot分区 3.创建LVM物理卷 4.生成卷组 5.创建逻辑卷 6.格式化安装 我们先用新安装Linux系统时的图形化界面,来演示一下LVM逻辑卷如何进行分区. 提 ...
- 关于java中的安全管理器
最近再查看java的源码的时候看见了这一类代码 final SecurityManager sm = System.getSecurityManager(); 想要了解这个是为了做什么,查看资料之后发 ...
- day03 Django目录结构与reques对象方法
day03 Django目录结构与reques对象方法 今日内容概要 django主要目录结构 创建app注意事项(重点) djago小白必会三板斧 静态文件配置(登录功能) requeste对象方法 ...
- day01 前端bootstrap框架
day01 django框架之bootstrap框架 今日内容概要 前端框架之bootstrap 该框架支持cv编写前端页面 利用socket模块编写一个简易版本的web框架 利用wsgiref模块编 ...
- 二叉树——Java实现
1 package struct; 2 3 interface Tree{ 4 //插入元素 5 void insert(int value); 6 //中序遍历 7 void inOrder(); ...
- 【编程思想】【设计模式】【行为模式Behavioral】模板模式Template
Python转载版 https://github.com/faif/python-patterns/blob/master/behavioral/template.py #!/usr/bin/env ...
- 【Linux】【Services】【Project】Cobbler自动化装机
1. 概念 1.1. Cobbler 1.2. PXE 1.3. 2. 版本信息 2.1. OS:Red Hat Enterprise Linux Server release 7.3 (Maipo) ...
- pandas基础学习一
生成对象 用值列表生成 Series 时,Pandas 默认自动生成整数索引: In [3]: s = pd.Series([1, 3, 5, np.nan, 6, 8]) In [4]: s Out ...
- 【前端】关于DOM节点
参考这个: https://juejin.cn/post/6844903849614901261 DOM树的根节点是document对象 DOM节点类型:HTML元素节点(element nodes) ...
- 【C/C++】最长无重复子数组
题目描述 给定一个数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同. 子数组是连续的,比如[1,2,3,4,5]的子数组有[1,2],[2,3,4]等等,但是[1,3, ...