多项式欧几里得除法(信息安全数学基础课设·)

题目:多项式广义的欧几里得除法

  • 数学基础

多项式广义Euclid除法:

设f(x),g(x)是域K上的多项式,deg g≥1。反复运用多项式Euclid除法,我们有

f(x) = q0g(x) + r0(x) ,        0≤deg r0<deg g(x)

g(x) = q1r0(x) + r1(x) ,       0≤deg r1<deg r0

r0(x) = q2r1(x) + r2(x) ,       0≤deg r2<deg r1

r1(x) = q3r2(x) + r3(x) ,       0≤deg r3<deg r2

……

rk-4(x) = qk-2rk-3(x) + rk-2(x) ,   0≤deg rk-2<deg rk-3

rk-3(x) = qk-1rk-2(x) + rk-1(x) ,   0≤deg rk-1<deg rk-2

rk-2(x) = qkrk-1(x) + rk(x) ,     rk(x)=0

经过有限个步骤,必然存在k使得rk(x)=0

  • 算法描述

我实现的是F2域上面的多项式欧几里得除法

模2除法需要用到模2加减法,关于模2加减法,其实就是异或操作,规则如下:

 

//不需要考虑进位和借位

0 ± 0 = 0

1 ± 1 = 0

0 ± 1 = 1

1 ± 0 = 1

例: 1101 ± 1001 = 0100

计算如下:

          1 1 0 1

        ± 1 0 0 1

        -----------

          0 1 0 0

简记:同为0,异为1

模2除法:

规则:假设被除数X,和除数P,余数R

1. 被除数X除以P(对X和P做模2加减法),被除数首位为1时,商1,为0时商0

2. 所得余数去除首位(左移一位):

- R第一位为0,将其作为新的被除数,除以0,此时其首位为0,商即为0

- R第一位为1,将其作为新的被除数,除以P,此时其首位为1,商即为1

3. 重复第2步直到R位数少于P位数

例:1111000对除数1101做模2除法:

先说结果: 商1011余111

整体运算

      1 0 1 1     //商

---------------

1 1 1 1 0 0 0     //被除数,注意首位为1

1 1 0 1           //被除数首位为1,除以除数

---------------

  0 1 0 0 0 0     //余数去除首位,作为新的被除数

  0 0 0 0         //被除数首位为0,除以0

---------------

    1 0 0 0 0     //余数去除首位,作为新的被除数

    1 1 0 1       //被除数首位为1,除以除数 

---------------

      1 0 1 0     //余数去除首位,作为新的被除数

      1 1 0 1     //被除数首位为1,除以除数

---------------

      0 1 1 1     //余数,此时余数位数少于除数,不能继续除了(忽略首位0)

  • 算法实现

f(x),g(x)多项式采用二进制码输入,如x+1用11表示,程序用全局静态变量static Vector<Integer> axstatic Vector<Integer> bx存储,a(x),b(x)是函数Euclidean 的两个参数,函数进行a(x)/b(x)操作,操作完成之后a(x)存储余数,b(x)值不变,于是再将b(x),a(x)带入Euclidean函数重复操作,直到余数即a(x)运算之后存储的内容为0.运算结束。

流程图如下:

Invert()函数是将vector存储的二进制码转化为多项式输出

   从开始到结束遍历,分四种情况:

1、当前位是1 且不是最后两位(x,1),输出 x的几次方形式

   if((i!=0)&(i!=1))

           System.out.print("x^"+i);

2当前位是1 且是最后一位输出1

if(i==0)

             System.out.print("1");

3当前位是1 且是倒数第二位输出 x

if(i==1)

   System.out.print("x");

4、输出加号规则最后一位不输出+,当前的后面存在是1 输出+

        if(i==0) continue;

        else if(a.get(asize-i)==0) continue;

        System.out.print("+");

 

Euclidean()函数用一个变量Vector<Integer> cx存储除得到的商,ax则在运算过程中不断变化。模2除法与长除法类似,但有个特点:不借位。说白了就是按位异或,相同为0,不同为1。

1、除数与被除数最高几位(与除数位数相同)做异或,商1。(除数首位必须为1) 用cx存储,ax每轮运算后去除首位数字,而且每轮循环对ax进行去0处理     否则ax=00001 会影响下一步运算

如果ax=00000,又会数组越界

 

2、余数先去掉首位,若此时余数最高位为1,商1,并对以它为除数继续模2除。

若最高位为0,则商0,重复步骤2。

3、直到余数位数小于除数位数时,运算结束。

for(int i=0;i<al-bl+1;i++) {

         cx.add(i, ax.get(0));

         int ax0 = ax.get(0);

         for(int j=0;j<bl;j++) {

           if(ax0==1)

           ax.set(j, (ax.get(j)+bx.get(j))%2);

         }

         ax.remove(0);

       }

       int ax_length=ax.size();

       for(int i=0;i<ax_length-1;i++) {

         if(ax.get(0)==0) ax.remove(0);//0处理

       }

 

主函数main中,不停进行Euclidean函数操作,只要rx不为0.每轮循环结束时借助中间变量rx交换ax与bx,以便开启下一轮循环。

步骤:      rx 清空;  a赋值给r;

            ax 清空;  b赋值给a;

            bx 清空;  r赋值给b;

while(true) {

         Euclidean(ax,bx);

         //循环结束条件

         int flag=0;

         for(int i=0;i<ax.size();i++) {

           if(ax.get(i)==1) flag=1;

         }

         if(flag==0) break;

         rx.clear();

         for(int i=0;i<ax.size();i++)     rx.add(i, ax.get(i));

         ax.clear();

         for(int i=0;i<bx.size();i++)     ax.add(i, bx.get(i));

         bx.clear();

         for(int i=0;i<rx.size();i++)     bx.add(i, rx.get(i));

       }

  • 运行结果

为方便区分,输出中用括号分开两多项式

 

 

啰嗦了这么多,现在上代码:


import java.util.Scanner;
import java.util.Vector;

public class test {
    static Vector<Integer> ax = new Vector<Integer>();
    static Vector<Integer> bx = new Vector<Integer>();
    static Vector<Integer> rx = new Vector<Integer>();//不是余数的意思,只是个中间变量
    public static void main(String[] args) {
        String a,b;
        //输入的数字转换成字符数组
        Scanner in = new Scanner(System.in);
        System.out.println("请输入a(x):");
        a = in.nextLine();
        char[] arraya = a.toCharArray();
        for(int i=0;i<a.length();i++)
            ax.addElement(arraya[i]-'0');
        
        
        System.out.println("请输入b(x):");
        b = in.nextLine();
        char[] arrayb = b.toCharArray();
        for(int i=0;i<b.length();i++)
            bx.addElement(arrayb[i]-'0');
        //输出ax,bx代表的多项式
        System.out.print("ax = ");  Invert(ax);  System.out.println();
        System.out.print("bx = ");  Invert(bx);     System.out.println();
        in.close();
        while(true) {
            Euclidean(ax,bx);
            //循环结束条件
            int flag=0;
            for(int i=0;i<ax.size();i++) {
                if(ax.get(i)==1) flag=1;
            }
            if(flag==0) break;
            /*ax <-> bx   交换ax,bx 以开启下一轮循环
               rx clear;  a->r;
               ax clear;  b->a;
               bx clear;  r->b;
               */
            rx.clear();
            for(int i=0;i<ax.size();i++)         rx.add(i, ax.get(i));
            ax.clear();
            for(int i=0;i<bx.size();i++)         ax.add(i, bx.get(i));
            bx.clear();
            for(int i=0;i<rx.size();i++)         bx.add(i, rx.get(i));
        }
        }
    
    //欧几里得除法 并以  ax = bx*cx + rx 形式输出
    public static void Euclidean(Vector<Integer> ax,Vector<Integer> bx) {
        int al = ax.size();
        int bl = bx.size();
        Vector<Integer> cx = new Vector<Integer>();
        Invert(ax);
        System.out.print(" = ");
        for(int i=0;i<al-bl+1;i++) {
            cx.add(i, ax.get(0));
            int ax0 = ax.get(0);
            for(int j=0;j<bl;j++) {
                if(ax0==1)
                ax.set(j, (ax.get(j)+bx.get(j))%2);
            }
            ax.remove(0);
        }
        //对ax进行去0处理     否则ax=00001 会影响下一步运算
        //如果ax=00000,又会数组越界
        int ax_length=ax.size();
        for(int i=0;i<ax_length-1;i++) {
            if(ax.get(0)==0) ax.remove(0);
        }
       
        System.out.print("(");
        Invert(bx);
        System.out.print(")(");
        Invert(cx);
        System.out.print(") + (");
        Invert(ax);        
        System.out.println(") ");
    }
    
    //vector->多项式输出
    public static void Invert(Vector<Integer> a) {
        int asize = a.size();
        for(int i=asize-1;i>=0;i--) {
            if(a.get(asize-1-i)==1){
                //当前位1 且不是最后两位输出 x的几次方形式
                if((i!=0)&(i!=1))
                    System.out.print("x^"+i);
                //当前位1 且是最后一位输出1
                if(i==0)
                    System.out.print("1");
                //当前位1 且是倒数第二位输出 x
                if(i==1)
                    System.out.print("x");
                }
            //最后一位不输出+,当前的后面存在是1 输出+ 
            if(i==0)    continue;
            else if(a.get(asize-i)==0) continue;
            System.out.print("+");
        }
    }
}
 

猜你喜欢

转载自blog.csdn.net/Drifter_Galaxy/article/details/86607960
今日推荐