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*sq*t其实在ab很大的时候有溢出的风险。

注意到这个问题之后,我用python实现了一下,果然!这个操作会溢出!又用python实现了一个matrix,这回没有这个问题。(我把代码放在最后)

结论

仔细看看这两种方法,第二种方法其实是一种推迟了减法的做法。矩阵上的元素始终在增长,且不会超过ab的最高位,代价就是多了两个需要存储的元素。

移位运算坑死我这样的小白

我修改了上面的代码,又测试了一下,还是不对,我慌了,最终使用中间量对比大法,一步一步去对比,人肉检查,我发现了问题所在。

实现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 记录:移位运算与扩展欧几里得算法的更多相关文章

  1. ****ural 1141. RSA Attack(RSA加密,扩展欧几里得算法)

    1141. RSA Attack Time limit: 1.0 secondMemory limit: 64 MB The RSA problem is the following: given a ...

  2. 『扩展欧几里得算法 Extended Euclid』

    Euclid算法(gcd) 在学习扩展欧几里得算法之前,当然要复习一下欧几里得算法啦. 众所周知,欧几里得算法又称gcd算法,辗转相除法,可以在\(O(log_2b)\)时间内求解\((a,b)\)( ...

  3. 扩展欧几里得算法详解(exgcd)

    一.前言 本博客适合已经学会欧几里得算法的人食用~~~ 二.扩展欧几里得算法 为了更好的理解扩展欧几里得算法,首先你要知道一个叫做贝祖定理的玄学定理: 即如果a.b是整数,那么一定存在整数x.y使得$ ...

  4. 初等数论-Base-2(扩展欧几里得算法,同余,线性同余方程,(附:裴蜀定理的证明))

    我们接着上面的欧几里得算法说 扩展欧几里得算法 扩展欧几里德算法是用来在已知a, b求解一组x,y,使它们满足贝祖等式\(^①\): ax+by = gcd(a, b) =d(解一定存在,根据数论中的 ...

  5. 扩展欧几里得算法(extgcd)

    相信大家对欧几里得算法,即辗转相除法不陌生吧. 代码如下: int gcd(int a, int b){ return !b ? gcd(b, a % b) : a; } 而扩展欧几里得算法,顾名思义 ...

  6. noip知识点总结之--欧几里得算法和扩展欧几里得算法

    一.欧几里得算法 名字非常高大上的不一定难,比如欧几里得算法...其实就是求两个正整数a, b的最大公约数(即gcd),亦称辗转相除法 需要先知道一个定理: gcd(a, b) = gcd(b, a  ...

  7. 欧几里得算法与扩展欧几里得算法_C++

    先感谢参考文献:http://www.cnblogs.com/frog112111/archive/2012/08/19/2646012.html 注:以下讨论的数均为整数 一.欧几里得算法(重点是证 ...

  8. vijos1009:扩展欧几里得算法

    1009:数论 扩展欧几里得算法 其实自己对扩展欧几里得算法一直很不熟悉...应该是因为之前不太理解的缘故吧这次再次思考,回看了某位大神的推导以及某位大神的模板应该算是有所领悟了 首先根据题意:L1= ...

  9. 浅谈扩展欧几里得算法(exgcd)

    在讲解扩展欧几里得之前我们先回顾下辗转相除法: \(gcd(a,b)=gcd(b,a\%b)\)当a%b==0的时候b即为所求最大公约数 好了切入正题: 简单地来说exgcd函数求解的是\(ax+by ...

随机推荐

  1. 大数据学习day34---spark14------1 redis的事务(pipeline)测试 ,2. 利用redis的pipeline实现数据统计的exactlyonce ,3 SparkStreaming中数据写入Hbase实现ExactlyOnce, 4.Spark StandAlone的执行模式,5 spark on yarn

    1 redis的事务(pipeline)测试 Redis本身对数据进行操作,单条命令是原子性的,但事务不保证原子性,且没有回滚.事务中任何命令执行失败,其余的命令仍会被执行,将Redis的多个操作放到 ...

  2. File类及常用操作方法

    import java.io.File; import java.io.IOException; public class file { public static void main(String[ ...

  3. 安装本地jar包到仓库

    1. 下载并解压 sdk 包本地文件夹下 2. 进入项目目录 执行以下操作之前,先确定 maven 的 settings 文件中 配置的 仓库地址是否为本项目的 仓库地址,如果不是,则会安装到其他仓库 ...

  4. maven 是什么?

    在了解maven的概念之前,我一直都在项目中使用maven,但是对于maven的了解,只能说连个皮毛都算不上,一直到项目中,自己机械化的deploy项目的时候,发现报错,赶紧报告开发组长,这私服是不是 ...

  5. js调用高德地图API获取地理信息进行定位

    <script type="text/javascript" src="http://webapi.amap.com/maps?v=1.3&key=(需要自 ...

  6. C++STL标准库学习笔记(三)multiset

    C++STL标准库学习笔记(三)multiset STL中的平衡二叉树数据结构 前言: 在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标 ...

  7. vs2019+windows服务+nancy+打包

    一.创建windows服务  二.nuget包添加nancy 1.nancy 2.0.0和Nancy.Hosting.Self 2.0.0插件 2.项目添加文件夹Modules,在Modules文件夹 ...

  8. vue双向绑定和深浅拷贝

    现象描述: vue 在使用的时候,当table绑定了某个data的时候.假如某个el-table-column下面的有个方法传参(data.row),然后在方法中用一个obj=data.row.(这里 ...

  9. Pytorch入门上 —— Dataset、Tensorboard、Transforms、Dataloader

    本节内容参照小土堆的pytorch入门视频教程.学习时建议多读源码,通过源码中的注释可以快速弄清楚类或函数的作用以及输入输出类型. Dataset 借用Dataset可以快速访问深度学习需要的数据,例 ...

  10. 【python】青果教务系统模拟登陆

    使用 python 的 selenium + chrome 来模拟登陆学校教务系统 完整代码传至 github,增加了一个自动识别验证码的功能,不过是用的别人的轮子,识别度也不高 这是需要手动输入验证 ...