求最大公约数有几种算法:1、辗转相除法,2、更相减损术,3、Stein算法。

Stein算法跟更相减损术很像,而且只有比较、移位、减法,非常适合用FPGA实现。

不了解这个算法的,可以先到百度百科看一下,Stein算法百度百科,此外,还要看看C语言实现的算法,百科那里的示例只有30行。

1、算法步骤。

那么,我把百科里面的算法步骤改写一下,让它更适合用verilog实现。

a、先装载A和B的值,C清零。

b、若A=0,则B是最大公约数;若B=0,则A是最大公约数;若A=B,则A是最大公约数。若上面三种情况都不成立,则跳到c,否则跳到d

c、 若A是偶数,B是偶数;则A>>1,B>>1,C<<1(LSB填充1);

若A是偶数,B是奇数;则A>>1,B不变,C不变;

若A是奇数,B是偶数;则A不变,B>>1,C不变;

若A是奇数,B是奇数;则if(A>B) A=A-B;else B=B-A,C不变;

d、输出结果。

同时,也把这四个步骤,抽象成状态机,分别是init,compare,calculate,finish。

接下来,要用状态机输出各种控制信号,来控制各个功能模块(always块),以实现不同的算法步骤。

2、示例代码。(请把代码copy到编辑器上观看,这里不容易排版)

module gcd(
input n_rst,clk,en,
input [7:0] Ain,Bin,
output reg [7:0] gcd_out='b0
);

localparam [1:0] init='b00,compare='b01,calculate='b11,finish='b10;
reg [1:0] cs='b0,ns='b0;
reg load='b0,comp_en='b0,cal_en='b0,out_en='b0,cal_over='b0;

reg [7:0] A_tmp='b0,B_tmp='b0,gcd_tmp='b0,shift_times='b0;
wire [1:0] A_B_LSB;

//three section FSM
//timing sequence part of FSM
always@(negedge  n_rst,posedge clk)
    if(!n_rst)
        cs<=init;
    else
        if(en)
            cs<=ns;

//combination part of FSM
always@(*)
    case (cs)
         init         :  ns<=compare;   
         compare      :  if (cal_over)
       ns<=finish;
    else
       ns<=calculate; 
         calculate    :  ns<=compare;
         finish       :  ns<=init;    
         default      :    ns<=init;      
    endcase
    
//register output part of FSM
always@(negedge n_rst,posedge clk)
    if(!n_rst)
        begin load<=1'b0;comp_en<=1'b0;cal_en<=1'b0; end
    else
        if(en)
            case(ns)
                 init       : begin load<=1'b1;comp_en<=1'b0;cal_en<=1'b0;out_en<=1'b0; end
                 compare    : begin load<=1'b0;comp_en<=1'b1;cal_en<=1'b0;out_en<=1'b0; end
                 calculate  : begin load<=1'b0;comp_en<=1'b0;cal_en<=1'b1;out_en<=1'b0; end
                 finish     : begin load<=1'b0;comp_en<=1'b0;cal_en<=1'b0;out_en<=1'b1; end
                 default    : begin load<=1'b0;comp_en<=1'b0;cal_en<=1'b0;out_en<=1'b0; end
            endcase

// whether the value is zero or not                       
always @(negedge n_rst or posedge clk) begin
   if (!n_rst) begin
     cal_over <= 1'b0;
     gcd_tmp  <= 'b0;
   end
   else 
    if (en) begin
       if (comp_en) begin
        if (A_tmp=='b0) begin
          cal_over <= 1'b1;
          gcd_tmp  <= B_tmp;
        end
        else begin
        if (B_tmp=='b0) begin
            cal_over <= 1'b1;
            gcd_tmp  <= A_tmp;
        end
        else begin
        if (A_tmp==B_tmp) begin
         cal_over <= 1'b1;
           gcd_tmp  <= A_tmp;
        end
        else begin
            cal_over <= 1'b0;
            gcd_tmp  <= 'b0;
        end 
        end 
    end
       end
   end
end

// calculate the gcd
assign A_B_LSB = {A_tmp[0],B_tmp[0]};//if A_tmp[0] = 0 , A_tmp is even and A_tmp >> 1,also as B_tmp;
always @(negedge n_rst or posedge clk) begin
if (!n_rst) begin
    A_tmp <= 'b0;
    B_tmp <= 'b0;
    shift_times<='b0;
end
    else 
     if (en) begin
    if (load) begin// load the initialization values
   A_tmp <= Ain;
   B_tmp <= Bin;
   shift_times<='b0;
    end 
    else begin
        if (cal_en) begin
        case (A_B_LSB)
            2'b00 :   begin A_tmp<={1'b0,A_tmp[7:1]};B_tmp<={1'b0,B_tmp[7:1]};
                 shift_times<={shift_times[6:0],1'b1};end
            2'b01 :   begin A_tmp<={1'b0,A_tmp[7:1]};B_tmp<=B_tmp;
                 shift_times<=shift_times;end
            2'b10 :   begin A_tmp<=A_tmp;B_tmp<={1'b0,B_tmp[7:1]};
                 shift_times<=shift_times;end
            2'b11 :   begin if (A_tmp>B_tmp) begin
                                A_tmp <= A_tmp-B_tmp;B_tmp <= B_tmp;
                            end
                            else begin
                                B_tmp <= B_tmp-A_tmp;A_tmp <= A_tmp;
                            end 
                            shift_times<=shift_times;
                      end
            default : begin A_tmp<=A_tmp;B_tmp<=B_tmp;shift_times<=shift_times;end
        endcase
        end
    end
    end
end

// output result , if enable  
always @(negedge n_rst or posedge clk) begin
  if (!n_rst) 
    gcd_out <= 'b0;
  else 
  if (en) begin
    if (out_en)
     if(cal_over)
     case (shift_times) 
         8'h00    :   gcd_out <= gcd_tmp;
         8'h01    :   gcd_out <= {gcd_tmp[6:0],1'b0};
         8'h03    :   gcd_out <= {gcd_tmp[5:0],2'b0};
         8'h07    :   gcd_out <= {gcd_tmp[4:0],3'b0};
         8'h0f    :   gcd_out <= {gcd_tmp[3:0],4'b0};
         8'h1f    :   gcd_out <= {gcd_tmp[2:0],5'b0};
         8'h3f    :   gcd_out <= {gcd_tmp[1:0],6'b0};
         8'h7f    :   gcd_out <= {gcd_tmp[0],7'b0};
         default  :   gcd_out <= gcd_tmp;
     endcase
    else begin
     gcd_out <= gcd_out;
    end
  end
end
                
endmodule

3、仿真结果。



4、其它问题。

a、为什么要装载A和B的值,而不用A和B端口的值?

端口上的值,只能读不能写,所以需要把A和B的值,装载到寄存器当中,这样,可读可写。而且,寄存器当中的值不受端口影响。

b、如何判断A和B的奇偶性?

很简单的,取A或B的最低位(LSB),LSB是1就是奇数,是0就是偶数。

c、为什么同样一个算法,用C只有30行,而verilog则用150行?

这就是软件和硬件的区别,由于C语言是交给算术逻辑单元(ALU)处理的,ALU本身具有串行的特性,这也就意味着你可以不用写状态机。而verilog则不同,需要你来写状态机。

d、为什么verilog不能像C语言一样,用while、函数嵌套?

这跟上面c的问题一样,区别在于有没有ALU。此外,用verilog的,必须考虑各个always块之间的协作关系,这也导致了verilog语言局部容易看懂,但是整体很难理解的特点。

5、进一步优化。

a、用parameter把上面的代码改成为位宽可以任意设定的。

b、比较用的if (A_tmp>B_tmp) 会因为位宽变大,而导致面积变大。可以把它换成减法,再判断MSB,以减小面积。

c、由于A*B=最大公约数*最小公倍数,那么,你应该可以写出最小公倍数算法。

最大公约数Stein算法之verilog实现相关推荐

  1. Stein算法(求两个数最大公约数)

    欧几里德算法是计算两个数最大公约数的传统算法,他无论从理论还是从效率上都是很好的.但是他有一个致命的缺陷,这个缺陷只有在大素数时才会显现出来. 考虑现在的硬件平台,一般整数最多也就是64位,对于这样的 ...

  2. 浅谈Stein算法求最大公约数(GCD)的原理及简单应用

    一.Stein算法过程及其简单证明 1.一般步骤: s1:当两数均为偶数时将其同时除以2至至少一数为奇数为止,记录除掉的所有公因数2的乘积k: s2:如果仍有一数为偶数,连续除以2直至该数为奇数为止: ...

  3. 求最大公约数和最小公倍数——辗转相除法(欧几里得算法)、更相减损术、stein算法

    辗转相除法-- 辗转相除法求最大公约数的原理: 两个整数其中较小的数 和 两数相除(较大数除较小数)的余数(使用递归)的最大公约数. 辗转相除法求最小公倍数的原理: 两个整数分别除以最大公约数的结果相 ...

  4. Python:三种方法计算最大公约数和最小公倍数(欧几里德法、穷举法、stein算法)

    Python:三种方法计算最大公约数和最小公倍数 1.穷举法 2.欧几里德法 3.Stein算法 题目:求取任意两个非负数(至多一个数为0)的最大公约数和最小公倍数: 参考资料:Python解决求最大 ...

  5. 最小公约数(欧几里得算法stein算法)

    求最小公约数,最容易想到的是欧几里得算法,这个算法也是比较容易理解的,效率也是很不错的.也叫做辗转相除法. 对任意两个数a,b(a>b),d=gcd(a,b),如果b不为零,那么gcd(a,b) ...

  6. 求最大公约数与最小公倍数 (辗转相除法+更相减损法+Stein算法)

    辗转相除法与更相减损法对比: (1)两者都是求最大公因数的方法,计算上辗转相除法以除法为主,更相减损术以减法为主,计算次数上辗转相除法计算次数相对较少,特别当两个数字大小区别较大时计算次数的区别较明显 ...

  7. 【最大公约数 GCD】 --- 常用四大算法(辗转相除法,穷举法,更相减损法,Stein算法)

    [最大公约数 GCD] --- 常用的四大算法 1. 辗转相除法(又名欧几里德算法) 2. 穷举法(也称枚举法) 3. 更相减损法 (又名辗转相减法) 4. Stein算法 1. 辗转相除法(又名欧几 ...

  8. 学习笔记 Stein算法

    介绍 Stein算法是一种计算两个数最大公约数的算法,是针对欧几里德算法在对大整数进行运算时,需要试商导致增加运算时间的缺陷而提出的改进算法. 欧几里得算法(辗转相除法)缺陷 欧几里德算法是计算两个数 ...

  9. 模逆(5.Stein算法)

    一.Stein算法 Stein算法是一种计算两个数最大公约数的算法,是针对欧几里德算法在对大整数进行运算时,需要试商导致增加运算时间的缺陷而提出的改进算法. 1.1 Stein算法 Stein算法是基 ...

最新文章

  1. 习题5-5 使用函数统计指定数字的个数 (15 分)
  2. 使用 html 标签嵌入Silverlight程序的一点小问题
  3. unet_3plus
  4. error C2061: 语法错误: 标识符“std”
  5. MvcPager帮助文档 - MvcAjaxOptions 类
  6. 母版页可以动态切换吗?
  7. 在Java中对Singleton类进行双重检查锁定
  8. 《C++ Primer 第五版》(第4.11节类型转换) ————关于无符号数和有符号数的运算探究
  9. 重启中的武汉:烟火气息回来了,消费疯狂增长
  10. 又被分治题卡住好几个小时!用最笨的方法搞懂分治法边界,告别死循环!
  11. linux的vmstat命令,Linux中vmstat命令起什么作用呢?
  12. java spring定时器_Spring定时器的使用
  13. Tik Tok与抖音的不同有哪些
  14. Java实战之管家婆记账系统(19)——报告界面及功能实现
  15. 联想拯救者y7000p加内存条_联想Y7000p加装金百达内存条,内存条细节多图
  16. Java冒泡排序实现
  17. 《东周列国志》第七十八回 会夹谷孔子却齐 堕三都闻人伏法
  18. 《MultiPoseNet: Fast Multi-Person Pose Estimation using Pose Residual Network》论文阅读
  19. C#读取srt字幕格式文件显示字幕
  20. 华为sug 6000 系列防火墙端口范围映射

热门文章

  1. 我要悄悄学数学、英语然后考研上岸!
  2. 第二篇:Fanuc网卡数据采集-刀具寿命数据
  3. Transformer是如何进军点云学习领域的?
  4. Visual Studio VS使用freopen调试控制台闪退
  5. 【测试】压力测试脚本录制
  6. 为治疗酒精成瘾,他们选择在大脑里植入电极。
  7. 在Ubuntu\Centos等Linux环境安装支付宝控件
  8. HP ZBOOK 笔记本电脑设置电池充电上限,防止过冲,保护电池
  9. 3使用高级元数据 ( yocto-kernel-cache)
  10. java swing 小游戏 炸弹人