整系数多项式的基本运算

  • 问题的引出
  • 多项式欧几里得除法
  • 多项式欧几里得除法的C语言实现
    • 倒置函数
    • 多项式加法
    • 多项式减法
    • 多项式乘法
    • 多项式除法
    • 主程序调用
    • 运行结果

问题的引出

在该博客中我将着手解决这样一个问题,在求解模素数ppp的同余式:
f(x)=anxn+⋯+a1x+a0≡0(modp)f(x)=a_nx^n+\cdots+a_1x+a_0\equiv0\left(modp\right) f(x)=an​xn+⋯+a1​x+a0​≡0(modp)
时,其中ana_nan​恒不为零. 通常需要借助费马小定理和多项式的欧几里得除法将上述一个复杂的问题转化为一个次数更低的模素数同余式。

具体来说,由费马小定理可知,多项式xp−x(modp)x^p-x\left(modp\right)xp−x(modp)对任何整数取值为零.进一步,利用多项式欧几里得除法可知存在整系数多项式q(x)q(x)q(x),r(x)r(x)r(x)使得:
f(x)=q(x)(xp−x)+r(x),deg(r(x))<deg(g(x)).f(x)=q(x)(x^p-x)+r(x), deg(r(x))<deg (g(x)). f(x)=q(x)(xp−x)+r(x),deg(r(x))<deg(g(x)).
从而容易将上述同余式:
f(x)=anxn+⋯+a1x+a0≡0(modp)f(x)=a_nx^n+\cdots+a_1x+a_0\equiv0\left(modp\right) f(x)=an​xn+⋯+a1​x+a0​≡0(modp)
降次为同余式:
r(x)≡0(modp)r(x)\equiv0\left(modp\right) r(x)≡0(modp)
不难证明上述两个模ppp同余式等价.这时我便将初始的问题转化为一个次数更低的模ppp同余式,进而方便原复杂问题的进一步求解。在这个化简过程中,起到核心作用的便是多项式的欧几里得除法,所以为了最终成功编程实现模素数ppp任意次同余式的求解,我需要首先编程实现整系数的多项式欧几里得除法.

多项式欧几里得除法

引理(多项式欧几里得除法):

f(x)=anxn+⋯+a1x+a0f(x)=a_nx^n+\cdots+a_1x+a_0 f(x)=an​xn+⋯+a1​x+a0​
为nnn次整系数多项式,
g(x)=xn+⋯+b1x+b0g(x)=x^n+\cdots+b_1x+b_0 g(x)=xn+⋯+b1​x+b0​
为m≥1m\ge1m≥1次首一整系数多项式,则存在整系数多项式q(x)q(x)q(x),r(x)r(x)r(x)使得:
f(x)=q(x)(xp−x)+r(x),deg(r(x))<deg(g(x)).f(x)=q(x)(x^p-x)+r(x), deg(r(x))<deg (g(x)). f(x)=q(x)(xp−x)+r(x),deg(r(x))<deg(g(x)).
证 :分以下两种情形讨论:
(i)(i)(i) n<mn<mn<m.取q(x)=0q(x)=0q(x)=0,r(x)=f(x)r(x)=f(x)r(x)=f(x),结论成立.
(i)(i)(i) n≥mn\ge mn≥m.对f(x)f(x)f(x)的次数nnn做数学归纳法.
对于 n=mn=mn=m,有
f(x)−ang(x)=(an−1−anbm−1)xn−1+⋯+(a1−anb1)x+a0−anbf(x)-a_ng(x)=(a_{n-1}-a_nb_{m-1})x^{n-1}+\cdots+(a_1 -a_n b_1 )x+a_0-a_nb f(x)−an​g(x)=(an−1​−an​bm−1​)xn−1+⋯+(a1​−an​b1​)x+a0​−an​b
因此,q(x)=an,r(x)=f(x)−ang(x)q(x)=a_n, r(x)=f(x)-a_ng(x)q(x)=an​,r(x)=f(x)−an​g(x)为所求.
假设n−1≥mn-1\ge mn−1≥m时,结论成立.
对于n>mn>mn>m,有
f(x)−anxn−mg(x)=(an−1−anbm−1)xn−1+⋯+(an−m−anb1)xn−m+an−m−1xn−m−1+⋯+a0−anbf(x)-a_nx^{n-m}g(x)=(a_{n-1}-a_nb_{m-1})x^{n-1}+\cdots+(a_{n-m} -a_n b_1 )x^{n-m}+a_{n-m-1}x^{n-m-1}+\cdots+a_0-a_nb f(x)−an​xn−mg(x)=(an−1​−an​bm−1​)xn−1+⋯+(an−m​−an​b1​)xn−m+an−m−1​xn−m−1+⋯+a0​−an​b
这说明f(x)−anxn−mg(x)f(x)-a_nx^{n-m}g(x)f(x)−an​xn−mg(x)是次数≤n−1\le n-1≤n−1的多项式。对其运用归纳假设,存在整系数多项式q1(x)q_1(x)q1​(x),r1(x)r_1(x)r1​(x)使得:
f(x)−anxn−mg(x)=q1(x)g(x)+r1(x),deg(r1(x))<deg(g(x)).f(x)-a_nx^{n-m}g(x)=q_1(x)g(x)+r_1(x), deg(r_1(x))<deg (g(x)). f(x)−an​xn−mg(x)=q1​(x)g(x)+r1​(x),deg(r1​(x))<deg(g(x)).
因此,q(x)=anxn−mg(x)+q1(x),r(x)=r1(x)q(x)=a_nx^{n-m}g(x)+q_1(x),r(x)=r_1(x)q(x)=an​xn−mg(x)+q1​(x),r(x)=r1​(x)为所求.

多项式欧几里得除法的C语言实现

我利用整形数组来代替多项式本身进行运算,进行整型数组的加减法和乘法运算,本质上是从右至左进行运算.而用多项式的系数进行运算时为了方便,我们总是默认将多项式的系数从高次至低次依次输入数组,这样直接调用数组元素会加重代码复杂度,降低代码的可读性. 因此,我想到一个解决这个问题简单的方法,就是在进行加减法和乘法之前,现将初始数组倒置,这样就可以直观的进行运算,最终将数组再次倒置,便于阅读.

倒置函数

int* Reverse(int *a, int Len)
{int tmp;for (int i = 0; i < Len / 2; i++){tmp = a[i];a[i] = a[Len - 1 - i];a[Len - 1 - i] = tmp;}return a;
}

多项式加法

int* PA(int * a, int Len1, int * b, int Len2)
{a = Reverse(a, Len1);//倒置数组ab = Reverse(b, Len2);//倒置数组bint Len3 = Max(Len1, Len2);//获得用于表示和多项式的数组的长度int *arr = (int*)malloc(Len3 * sizeof(int));//为和多项式的数组开辟动态内存空间if (Len1 == Len3)//将多项式最高次的次数高的数组赋给新的数组for (int i = 0; i < Len1; i++)arr[i] = a[i];elsefor (int i = 0; i < Len3; i++)arr[i] = b[i];if (Len1 != Len3)//将多项式最高次的次数低的数组与新数组相加for (int i = 0; i < Len1; i++)arr[i] += a[i];elsefor (int i = 0; i < Len2; i++)arr[i] += b[i];arr = Reverse(arr, Len3);//倒置和多项式的数组,以便该数组直接表示和多项式从高至低的系数a = Reverse(a, Len1);//保持输入数组a不变b = Reverse(b, Len2);//保持输入数组b不变return arr;
}

多项式减法

int* PS(int * a, int Len1, int * b, int Len2)
{a = Reverse(a, Len1);//倒置数组ab = Reverse(b, Len2);//倒置数组bint Len3 = Max(Len1, Len2);//初步获得用于表示余式的数组的长度(可能比这个长度低,因为数组a和数组b的前多个髙次项系数和次数完全一样)int *arr = (int*)malloc(Len3 * sizeof(int));//为余式的数组开辟动态内存空间if (Len1 == Len3)//若数组a的长度大于等于数组b的长度,只需将数组a赋给新数组,再将数组a的前Len2个元素分别减掉数组b对应的元素{for (int i = 0; i < Len1; i++)//arr[i] = a[i];for (int i = 0; i < Len2; i++)arr[i] -= b[i];}else//若数组a的长度小于数组b的长度,先将数组a赋给新数组的前Len1个元素,再用数组a的元素分别减掉数组b对应的前len1个元素,最终将数组b的后Len3-Len1个元素置负后赋给新数组的后半部分{for (int i = 0; i < Len1; i++)arr[i] = a[i];for (int i = 0; i < Len1; i++)arr[i] -= b[i];for (int i = Len1; i < Len2; i++)arr[i] = -b[i];}arr = Reverse(arr, Len3);//倒置余式的数组,以便该数组直接表示余式从高至低的系数//由于数组a和数组b的前多个髙次项系数和次数完全一样,所以上述操作结束后余式数组arr可能前几项元素为0,即余式系数不再等于输入多项式的最高次项。//而输出的数组应该保留至首个非零的元素,即将系数为零的高次项消除。所以我们需要将余式从高次至低次检查系数是否为零,确保返回的余式首系数不为零。int count = 0;//用于记录余式数组arr需要出掉多少个零元素for (int i = 0; i < Len3; i++)//从左至右判断arr元素是否为零{if (arr[i] == 0)count++;elsebreak;//一旦出现非零元素便跳出循环}if (count != 0)//判断数组arr所代表的余式是否需要保留首个系数不为零及之后的项{int *brr = (int*)malloc((Len3 - count) * sizeof(int));//为首个系数不为零及之后的项分配内存for (int i = 0; i < Len3 - count; i++)//从数组arr首个不为零的元素开始依次赋值给数组brrbrr[i] = arr[i + count];free(arr);//释放最初数组arrarr = brr;//将数组brr的首地址赋给arrbrr = NULL;//将数组brr置空}a = Reverse(a, Len1);//保持输入数组a不变b = Reverse(b, Len2);//保持输入数组b不变return arr;
}

多项式乘法

int* PM(int * a, int Len1, int * b, int Len2)
{a = Reverse(a, Len1);//倒置数组ab = Reverse(b, Len2);//倒置数组bint *arr = (int*)calloc(Len1 + Len2, sizeof(int));//为积多项式的数组开辟动态内存空间,并顺便将每个元素赋值为0for (int i = 0; i < Len2; i++)//用数组b的元素分别去乘数组afor (int j = 0; j < Len1 ; j++)arr[j+i] += b[i] * a[j];//并向左依次移一维arr = Reverse(arr, Len1 + Len2 - 1);//倒置积多项式的数组,以便该数组直接表示积多项式从高至低的系数a = Reverse(a, Len1);//保持输入数组a不变b = Reverse(b, Len2);//保持输入数组b不变return arr;
}

多项式除法

int* PD(int * a, int Len1, int * b, int Len2)
{if (b[0] != 1)//除式首系数不为1,则该程序无法解决这样的多项式除法return 0;int count;//记录每次做差时,被减式与减式从左至右连续相同的位数int Len11 = Len1;//初始化被减式的位数int count2 = 0;//用于记录除法进行到哪一位int *Q = NULL;//初始化商式int *tmp1 = NULL;//初始化减式int* tmp2 = a;//初始化被减式(刚开始即为数组a)int *tmp3 = a;//初始化中间被差式(也是每一步的余式)while (Len11 >= Len2)//判断余式的最高次数是否小于除式的最高次数,若小于,那么多项式除法结束并返回最新的余式;若大于,那么多项式除法继续进行{printf("第 %d 次循环\n", count2);count = 0;//每次循环需要重新初始化被减式与减式从左至右连续相同的位数if (a[count2] == 0 && tmp2[1]==0)//判断这一循环位是否商零,若商零,用于记录除法进行到哪一位的count2自动加一,且直接进入下一个循环{count2++;continue;}else{printf("Len11 is %d\n", Len11);printf("count2 is %d\n", count2);Q = (int*)calloc(Len11 + 1 - Len2, sizeof(int));//分配本次循环的商式的内存。Q[0] = tmp2[0];//将被减式的首元素赋给商式的首元素printf("Q is \n");for (int j = 0; j < Len11 + 1 - Len2; j++)printf("%d", Q[j]);printf("\n");tmp1 = (int*)malloc((Len11) * sizeof(int));//为本次循环的减式分配内存printf("LenQ is %d\n", Len11 + 1 - Len2);tmp1 = PM(Q, Len11 + 1 - Len2, b, Len2);//计算本次循环的减式printf("tmp1 is \n");for (int j = 0; j < Len11; j++)printf("%d", tmp1[j]);printf("\n");for (int i = 0; i < Len11; i++)//记录本次循环被减式与减式从左至右连续相同的位数if (tmp1[i] == tmp2[i])count++;elsebreak;printf("count is %d\n", count);printf("count2 is %d\n", count2);tmp3 = (int*)calloc(Len11 - count, sizeof(int));//为本次循环的余式分配内存printf("Len11 is %d\n", Len11);printf("Lentmp3 is %d\n", Len11 - count);tmp3 = PS(tmp2, Len11, tmp1, Len11);//计算本次循环的余式printf("tmp3 is \n");for (int i = 0; i < Len11 - count; i++)printf("%d", tmp3[i]);printf("\n");tmp2 = NULL;//每次循环到达这一步时,我们已经计算出了下一次循环的被除式,即tmp3,因此我们把旧的被除式置空tmp2 = tmp3;//并将新的被除式tmp3赋给tmp2printf("tmp2 is \n");for (int i = 0; i < Len11 - count; i++)printf("%d", tmp2[i]);printf("\n");Len11 = Len11 - count;//计算下次循环减式的长度count2++;printf("\n");printf("\n");}}return tmp2;//返回最新的余式,
}

主程序调用

我在这里会举出一个实际的例子:
求同余式:
f(x)=3x14+4x13+2x11+x9+x6+x3+12x2+x≡0(mod5),f(x)=3x^{14}+4x^{13}+2x^{11}+x^9+x^6+x^3+12x^2+x\equiv 0 (mod 5), f(x)=3x14+4x13+2x11+x9+x6+x3+12x2+x≡0(mod5),
等价的次数小于5的同余式:r(x)r(x)r(x).

int main()
{int a[] = { 3,4,0,2,0,1,0,0,1,0,0,1,12,1,0 };int b[] = { 1,0,0,0,-1,0 };int Len1 = sizeof(a) / sizeof(a[0]);int Len2 = sizeof(b) / sizeof(b[0]);int *f = PD(a, Len1, b, Len2);for (int i = 0; i < 4; i++)printf("%d ", f[i]);free(f);_getch();return 0;
}

运行结果


也就是说:
f(x)=3x14+4x13+2x11+x9+x6+x3+12x2+x≡0(mod5),f(x)=3x^{14}+4x^{13}+2x^{11}+x^9+x^6+x^3+12x^2+x\equiv 0 (mod 5), f(x)=3x14+4x13+2x11+x9+x6+x3+12x2+x≡0(mod5),
在模5的意义下与:
3x3+16x2+6x3x^3+16x^2+6x 3x3+16x2+6x
等价.在这个问题中我们的除式选择为:
x5−xx^5-x x5−x
原因只需要用费马小定理解释即可!

注:在解决这个问题的过程中,我使用的编译器为Visual Studio 2017,
不同版本的编译器在使用我的代码的过程中可能需要简单调试,这里因给大家造成不便而表示歉意.

多项式除法的C语言实现相关推荐

  1. 【学习笔记】超简单的多项式除法(含完整证明)

    整理的算法模板合集: ACM模板 目录 多项式除法 P4512 [模板]多项式除法 tips 还没调出来的vector版本代码 点我看多项式全家桶(●^◡_◡◡​^●) 多项式除法 P4512 [模板 ...

  2. P4512 【模板】多项式除法

    题意:多项式除法,A(x)=C(x)*B(x)+D(x),给定A(x),B(x),求C(x),D(x) 题解:A(x)的度是n,B(x)的度是m 定义\(A'(x)=x^n*A(\frac{1}{x} ...

  3. deconv--反褶积和多项式除法

    [功能简介]求向量反褶积和进行多项式除法运算. [语法格式] [q,r]=deconv(v,u) 参数q和r分别返回多项式v除以多项式u的商多项式和余多项式. [实例3.33]求多项式(x2+2x+1 ...

  4. luogu P4512 多项式除法 (模板题、FFT、多项式求逆)

    luogu P4512 多项式除法 (模板题.FFT.多项式求逆) 手动博客搬家: 本文发表于20181206 14:42:53, 原地址https://blog.csdn.net/suncongbo ...

  5. 多项式除法,多项式取模

    多项式除法 给定一个nnn次多项式F(x)F(x)F(x)和mmm次多项式G(x)G(x)G(x),要求R(x),Q(x)R(x), Q(x)R(x),Q(x),满足F(x)=R(x)G(x)+Q(x ...

  6. 多项式算法7:多项式除法

    多项式算法7:多项式除法 多项式除法 前置知识: FFT NTT 多项式求逆 多项式除法 算法简述: 给定多项式FFF , GGG求出多项式RRR,QQQ使得F=G×Q+RF=G \times Q + ...

  7. C++多项式除法的探讨

    最近的一项工作就是用vector实现多项式类,这个类需要完成多项式的数据结构的定义以及基本运算,包括加减乘除,前三个还比较容易,对于多项式的除法,因为有除不尽的情况,比如: 计算 其结果是: 明显是除 ...

  8. PTA L2-018 多项式A除以B (多项式除法)

    L2-018 多项式A除以B (25 分) 这仍然是一道关于A/B的题,只不过A和B都换成了多项式.你需要计算两个多项式相除的商Q和余R,其中R的阶数必须小于B的阶数. 输入格式: 输入分两行,每行给 ...

  9. 基于MATLAB 2014b的多项式除法程序

    多项式运算所涉及的函数见下表 conv 实现卷积和多项式乘法 deconv 实现去卷积和多项式除法 poly 求具有指定根的多项式 polyder 多项式求导 polyeig 求多项式的特征值 pol ...

最新文章

  1. MySQL 备份和恢复策略
  2. WebMvcConfigurerAdapter过时了替代的方法
  3. 自动装箱,拆箱和NoSuchMethodError
  4. Windows平台下动态链接库的总结
  5. iOS开发多线程篇—线程的状态
  6. (转)调用System.gc没有立即执行的解决方法
  7. SubSonic:一个对象的引用是必需的对于非静态字段
  8. Python 集合 day3
  9. Could not initialize English chunker/Could not load file from classpath: ‘/en-token.bin‘
  10. 5G~ SON和MDT
  11. python处理词项的停用词_词项邻近 停用词 词干还原
  12. 如何让百度快速收录网站及文章
  13. 拒绝“重复造轮子”,百度EasyDL让你玩转AI定制开发
  14. 超级授权专业版 SuperSU Pro v2.68 简体中文版
  15. 广义相对论和狭义相对论到底是讲什么的?
  16. 三菱FX5U连接MQTT
  17. 0002、Freemarker导出Word文档
  18. c语言编译器字体怎么变大,c语言中怎么将个别字体放大,如9,将其放大,怎么编程呢?...
  19. Java——entity(实体类)的写法规范
  20. 五、DML(数据操纵语句)

热门文章

  1. P2858 [USACO06FEB]Treats for the Cows G/S 题解
  2. Python字符串详解(2)
  3. 什么是数据库,为什么要有数据库?
  4. JS逆向之某头条jsvmp逻辑层算法分析
  5. 面试奇淫巧技之——STAR法则+BEI面试大法
  6. Verilog数字系统基础设计-CRC
  7. LibQQt系列之十六《QQt版本划分》
  8. 了解Adobe Illustrator的网格系统
  9. 5G时代,视频到底是不是下一个移动互联网的风口?
  10. SuperSlider 2.x 无缝滚动在IE浏览器的兼容问题