系列文章目录


文章目录

  • 系列文章目录
  • 前言
  • 一.最大公因式
    • 1.定义:
    • 2.说明:
  • 二.辗转相除法
    • 1.带余除法
    • 2.引理
    • 3.辗转相除法求最大公因数
    • 4.辗转相除法求最小公倍数
  • 三.C语言实现
    • 1.目标
    • 2.多项式的传入
    • 3.函数传参
    • 4.创建变量
    • 5.内存交换函数
    • 6.返回值的设置
    • 7.辗转相除
    • 8.化简系数
  • 四.完整代码
    • 总结

前言

本系列为使用C语言实现实用的数学公式


一.最大公因式

1.定义:

设f(x),g(x) ∊ P[x]. 若有d(x) ∊ P[x]满足
(i) d(x)是f(x),g(x)的公因式.
(ii) f(x),g(x)的公因式全是d(x)的因式.
则称d(x)为f(x)与g(x)的一个最大公因式.

2.说明:

最大公因式在相差一个非零常数的意义下是唯一确定的
即d₁(x) | d₂(x), d₂(x) | d₁(x)
由整除的性质知: d₁(x)=c d₂(x).

二.辗转相除法

1.带余除法

设f(x) , g(x) ∊ P[x], g(x) != 0,则存在唯一的多项式q(x), r(x) ∊ P[x]
使 f(x) = q(x) g(x) + r(x) 其中r(x)=0 或 ∂(r(x)) < ∂(g(x)).
称上式中的q(x) 为g(x) 除f (x)的商,r(x)为g(x)除f (x)的余式.

2.引理

设f(x),g(x) ∊ P[x].如果等式f(x) = q(x)g(x) + r(x)
成立,则f(x),g(x) 和g(x),r(x)有相同的公因式.
(这里毕竟是用C语言去实现该功能,感兴趣的朋友可以自行查阅,就不在这里证明了)

3.辗转相除法求最大公因数

//辗转相除法求最大公因数
int GCF(int A, int B) {while (A % B) {int tmp = A % B;A = B;B = tmp;}return B;
}

4.辗转相除法求最小公倍数

//辗转相除法求最小公倍数
int LCM(int A, int B) {int AM = A;int BM = B;int RET = 0;while (A % B) {int tmp = A % B;A = B;B = tmp;}RET = AM / B * BM; return RET;
}

这里即是让大家了解一下辗转相除法的思想,也是帮那些只需要这段代码的朋友们节省时间[doge]

三.C语言实现

1.目标

首先,我们的目标是通过带余除法,让两个多项式辗转相除法得到一个余式,使得这个余式与除式再一次相除,依此类推直到得到一个最高次幂为0的余式。这里我们要清楚我们需要一个循环来进行多次相除。

2.多项式的传入

首先,我们面临的第一个问题是如何传入一个多项式,很显然同时将各项的系数和次数同时传入一个数组是一件非常困难且混乱的事情。这时我们应该去寻找两个多项式共同具有的特点,他们的次数都是0~n递增。这里是不是似曾相识啊?是的,这不就是数组的下标嘛!问题迎刃而解,我们只需要按照对应的下标储存该次项所对应的系数就行了,是不是超级简单!
这里我才用的是先输入最高次幂,然后依此从高到低输入各次项系数,好处就是在输入的时候不会混乱,并且简化了输入的难度,和代码实现的难度。

//多项式一int N1 = 0;                                    // 最高次幂long COE1[20] = {0};                           // 各项系数printf("多项式(一)的最高次幂:>");scanf("%d", &N1);for (int i = N1; i >= 0; i--) {printf("请输入 %d 次幂的系数:>", i);scanf("%ld", COE1 + i);}//多项式二int N2 = 0;                                    // 最高次幂long COE2[20] = {0};                           // 各项系数printf("多项式(二)的最高次幂:>");scanf("%d", &N2);for (int i = N2; i >= 0; i--) {printf("请输入 %d 次幂的系数:>", i);scanf("%ld", COE2 + i);}

3.函数传参

写代码要尽量去做到高内聚低耦合并具有较高的可移植性,我们不能仅仅为了实现这一个功能让他只能在这个空间内跑动。正如程序员不能只会在一个编译器上敲代码,换成个编辑器就什么都不会了。所以当我们时,要让他可以在其他程序里运行,我们就要将其写成一个函数,在需要时随时调用。

想做一劳永逸的事情并非那么容易。首先我们要让函数内部知道这个多项式是几次幂,这里就用到了我们上一步输入时的最高次幂N1和N2,其次传入两个数组。此时问题再一次接踵而至,我们需要让他返回一个多项式,并且不能破坏原先的数组。在函数内部创建的数组是临时变量,你没有办法将地址返回到main里,临时变量的生命周期在它所在的函数结束时一并结束。这里我们在传入一个ret用于接收函数运行结果所得的多项式的最高次幂,同时一个RET用于接收最大公因式各项的系数。

4.创建变量

由于我们要确保啊函数的安全运行,这里我们对空指针进行一下断言。然后我们原则上不可以改变原先数组的内容,我们要重新创建数组,将里面的内容拷贝到临时数组中。这里创建的指针MAX和MIN目的是为了确定次数较高的多项式和较低的多项式,当MIN > MAX时两者进行地址交换。

// 返回系数数组 指针函数:(次数1, 系数数组1, 次数2, 系数数组2, 返回次数, 返回系数数组)
long *EuclideanAlgorithm(int max, const long *COE1, int min, const long *COE2, int *ret, long *RET) {//空指针断言assert(COE1 && COE2 && RET);//创建变量并赋值long M1[20] = {0};long M2[20] = {0};long *MAX = M1;long *MIN = M2;memcpy(M1, COE1, (max + 1) * 8);memcpy(M2, COE2, (min + 1) * 8);
}
    //判断次数大小if (max < min) {long *TMP = MAX;MAX = MIN;MIN = TMP;memchange(&max, &min, sizeof(max)); //内存交换函数}

5.内存交换函数

内存交换函数,这里我选择的是进行每个字节的内存交换 ,这里实现的时候要之分注意,只能交换两个同类型变量的内容。void *可以用来接收任意类型变量的地址,len是这两个变量的类型所占bit位数。按找char类型一个bit一个bit进行交换。

//内存交换
void memchange(void *A, void *B, int len) {while (len--) {char tmp = *(char *) A;*(char *) A = *(char *) B;*(char *) B = tmp;A = (char *) A + 1;B = (char *) B + 1;}
}

6.返回值的设置

此时的我们先假设功能已经实现完成,由于辗转相除往往不能一次就算出最大公因式,所以需要用循环语句多次执行。

我们不妨假设,多项式MAX除以MIN时一下子就出尽了。我们此时此刻并不清楚辗转相除功能是如何实现的,所以我们可以选择在步入到辗转相除功能之前,将MIN的地址和它系数的值赋给RET和ret就可以了。即使在运行过程中对变量造成改变,也不影响RET和ret的返回值。此时此刻我们就有了一个大的框架。

long *EuclideanAlgorithm(int max, const long *COE1, int min, const long *COE2, int *ret, long *RET) {//空指针断言assert(COE1 && COE2 && RET);//创建变量并赋值long M1[20] = {0};long M2[20] = {0};long *MAX = M1;long *MIN = M2;memcpy(M1, COE1, (max + 1) * 8);memcpy(M2, COE2, (min + 1) * 8);while (max > 0) {//判断次数大小if (max < min) {long *TMP = MAX;MAX = MIN;MIN = TMP;memchange(&max, &min, sizeof(max));}/*** 记录返回值*/*ret = min;memcpy(RET, MIN, 160);//函数功能始/*** 内容*///函数功能终}
}

7.辗转相除

现在我们到了最为重要的一步,如何实现辗转相除?


简单来说就是消去MAX的最高次幂,那么晚们首先要用到的就是MIN的最高次幂的的系数。
条件:存在一个倍数A,使得当MIN的最高次幂系数乘以A时,必有(MIN的首项系数 * A) == (MAX的系数)
这样我们就将MAX的最高次幂消去了,当然MIN的其余项系数也要乘以A。

思路非常明了对不对,但是!!!当遇到A为无理数该怎么办?你除不尽啊!

这里我们依然要用到最大公因式的思想,我们要做的就是求出这两个最高次幂系数的最大公因数,然后让两个系数分别除以最大公因数得出与之对应的倍数num1和num2,而num1和num2一定是互素的。接着我们让求出的num1与MIN的各项系数相乘,num2与MAX的各项系数相乘,这样我们就得到了这两个多项式首项的最小公倍数。由于我的最大公倍数求出来可能会很大所以这里系数用是长整形。这样即达到了消去首项的目的,又满足了倍数为一个整数,这样是不是让问题变得超级简单了!这里我们可以单独写一个求最大公因数的函数。

//求最大公因数
long GCF(long A, long B) {if (A < B) {memchange(&A, &B, sizeof(A));}while (A % B) {long tmp = A % B;A = B;B = tmp;}return B;
}
    long num = GCF(MAX[max], MIN[min]);long num1 = MAX[max] / num;long num2 = MIN[min] / num;for (int i = 0; max - i + 1; i++) {MAX[max - i] *= num2;}for (int i = 0; min - i + 1; i++) {MIN[min - i] *= num1;}

我们现在有了两整理好的多项式,只需要让他们相减就可以了,在这里我们要对MAX的最高次幂max进行变动,所以设置一个临时的Tmax = max来替代max。将两式相减后的各项系数重新赋值给MAX,如果相减结果为0,且比它更高次幂的项系数也为0,那么我们就让max–来降低它的最高次数。如果遇到了系数非零的项,那么比他次数底,但系数为0那么max也将不会再改变。这里我用的是 && 运算符如果前面条件成立,则运算后面条件,如果前面条件不成立,则不运算后面的条件的特性。

    //两式相减int stop = 0;     // stop用于自高次向低次,遍历两个多项式相减所得的新多项式,系数是否为0,如果遇到不为0系数则停止遍历long Tmax = max;  // max要进行变动,创建临时变量Tmax取代max的位置for (int i = 0; min - i + 1; i++) {MAX[Tmax - i] -= MIN[min - i];if (!MAX[Tmax - i] && !stop && !max--) {} else if (MAX[Tmax - i]) {stop++;}}

8.化简系数

我们前面用最小公倍数的方法将最高次幂项消去,这势必会让系数过大,这里我们只需要再次求各项的最大公因数,然后让各项除以所得的最大公因数就可以了。

    int count = *RET;for (int i = 1; i <= *ret; i++) {count = GCF(count, *(RET + i));}for (int i = 0; i <= *ret; i++) {RET[i] /= count;}

啊哈!这样一步一步走下来是不是让问题变得超级简单了,其实问题也没有那么复杂不是吗!
嘿嘿!当然,这是用来让大家锻炼一种解决问题的思考方式的,大家可千万不要用来偷懒写高代线代的作业啊![doge]


四.完整代码

#include <stdio.h>
#include <string.h>
#include <assert.h>//实数域多项式求最大公因式//内存交换
void memchange(void *A, void *B, int len) {while (len--) {char tmp = *(char *) A;*(char *) A = *(char *) B;*(char *) B = tmp;A = (char *) A + 1;B = (char *) B + 1;}
}//求最大公因数
long GCF(long A, long B) {if (A < B) {memchange(&A, &B, sizeof(A));}while (A % B) {long tmp = A % B;A = B;B = tmp;}return B;
}//辗转相除法求多项式的最大公因式
// 返回系数数组 指针函数:(次数1, 系数数组1, 次数2, 系数数组2, 返回次数, 返回系数数组)
long *EuclideanAlgorithm(int max, long *COE1, int min, long *COE2, int *ret, long *RET) {//空指针断言assert(COE1 && COE2 && RET);//创建变量并赋值long M1[20] = {0};long M2[20] = {0};long *MAX = M1;long *MIN = M2;memcpy(M1, COE1, (max + 1) * 8);memcpy(M2, COE2, (min + 1) * 8);while (max > 0) {//判断次数大小if (max < min) {long *TMP = MAX;MAX = MIN;MIN = TMP;memchange(&max, &min, sizeof(max));}/*** 记录返回值*/*ret = min;memcpy(RET, MIN, 160);/*** 最小公倍数*/long num = GCF(MAX[max], MIN[min]);long num1 = MAX[max] / num;long num2 = MIN[min] / num;for (int i = 0; max - i + 1; i++) {MAX[max - i] *= num2;}for (int i = 0; min - i + 1; i++) {MIN[min - i] *= num1;}/*** 两式相减*/int stop = 0;     // stop用于自高次向低次,遍历两个多项式相减所得的新多项式,系数是否为0,如果遇到不为0系数则停止遍历long Tmax = max;  // max要进行变动,创建临时变量Tmax取代max的位置for (int i = 0; min - i + 1; i++) {MAX[Tmax - i] -= MIN[min - i];if (!MAX[Tmax - i] && !stop && !max--) {} else if (MAX[Tmax - i]) {stop++;}}}//化简系数int count = *RET;for (int i = 1; i <= *ret; i++) {count = GCF(count, *(RET + i));}for (int i = 0; i <= *ret; i++) {RET[i] /= count;}return RET;
}int main() {//多项式一int N1 = 0;                                    // 最高次幂long COE1[20] = {0};                           // 各项系数printf("多项式(一)的最高次幂:>");scanf("%d", &N1);for (int i = N1; i >= 0; i--) {printf("请输入 %d 次幂的系数:>", i);scanf("%ld", COE1 + i);}//多项式二int N2 = 0;                                    // 最高次幂long COE2[20] = {0};                           // 各项系数printf("多项式(二)的最高次幂:>");scanf("%d", &N2);for (int i = N2; i >= 0; i--) {printf("请输入 %d 次幂的系数:>", i);scanf("%ld", COE2 + i);}//函数传惨int ret = 0;            //接收返回多项式的最高次数long RET[20] = {0};     //接收返回的多项式EuclideanAlgorithm(N1, COE1, N2, COE2, &ret, RET);//打印多项式的系数ret += 1;while (ret--) {printf("%d次方的系数为:%ld\n", ret, RET[ret]);}return 0;
}

总结

本文详细讲述了线性代数中,求多项式的最大公因式的方法,未来博主会继续更新相关数学函数的实现,欢迎大家交流学习。

代码实现 —— 多项式的最大公因式(线性代数)相关推荐

  1. 辗转相除法求多项式的最大公因式

    求(f,g) deg(f)>=deg(g) f=g·h+r r为0时,(f,g)=g r!=0时,(f,g)= (g,r) 求(g,r) deg(g)>deg® g=r·h1+r1 r1为 ...

  2. NTL密码算法开源库(数论库)代码分析项目--综述

    2021SC@SDUSC NTL密码算法开源库(数论库)代码分析项目--综述 项目综述 NTL开源代码库的安装和使用 NTL代码开源库主要解决的问题 项目分工以及核心代码的分配 项目综述 NTL算法库 ...

  3. 行列式因子、不变因子、初等因子、smith标准型、Jordan标准型、最小多项式的matlab实现

    版权声明:<–本博客所有内容均为自己在学习工作中的总结.摘录等-- --转载请注明出处-- --如有侵权请联系删除–> https://blog.csdn.net/ai359005521/ ...

  4. NTL密码算法开源库——大整数上多项式(ZZX,GF2X)

    2021SC@SDUSC 大整数上多项式(ZZX,GF2X) GF(2)域求两多项式的最大公因式 扩展欧几里得求两多项式最大公因式 GF(2)域求两多项式的最大公因式 //在GF(2)域中求两多项式的 ...

  5. ML与math:机器学习与高等数学基础概念、代码实现、案例应用之详细攻略——进阶篇

    ML与math:机器学习与高等数学基础概念.代码实现.案例应用之详细攻略--进阶篇 目录 人工智能数学基础综合 人工智能数学基础之高等数学 1.哈夫曼编码Huffman Coding简介及代码实现 人 ...

  6. 【最新合集】PAT甲级最优题解(题解+解析+代码)

    以下每道题均是笔者多方对比后, 思考整理得到的最优代码,欢迎交流! 共同成长哇.可以和博主比拼一下谁刷的更快~ 欢迎收藏.欢迎来玩儿 PAT题解目录 题号 标题 题解 分类 使用算法 1001 A+B ...

  7. 多项式辗转相除法求最大公约数_点灯游戏、方格填数与 Chebyshev 多项式(续)...

    本文是上一篇文章的续集. 预告:上篇文章说过的基解可视化在本文末尾,不想看中间推导过程的可以直接拉到最底下看图.个人觉得这些图都相当地优美,大概这就是数学的魅力吧. Chebyshev 多项式的性质 ...

  8. 重构:改善既有代码的设计_技术债务:通过重构来拯救传统代码

    重构:改善既有代码的设计 How can you get a legacy codebase under control and bring it to a new level of maturity ...

  9. L2-018. 多项式A除以B

    L2-018. 多项式A除以B 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 这仍然是一道关于A/B的题,只不过A和B都换成了 ...

最新文章

  1. SourceTree安装破姐添加SSH KEY以及拉取代码教程(附资源下载)
  2. ubuntu11.04服务器安装
  3. odciexttableopen 调用出错 error open log_如何在 Spring 异步调用中传递上下文
  4. jQuery.ajax success 与 complete 区别
  5. file获取文件后缀_Python 工匠:高效操作文件的三个建议
  6. nagios 飞信(fetion) 短信报警
  7. ASP.net在页面所有内容生成后、输出内容前对页面内容进行操作
  8. MySQL--当事务遇到DDL命令
  9. matlab node._matlab调用ansys
  10. 【经典产品思维】引领“用户消费”的产品怎么做?
  11. 音色、音高、音强、音长
  12. 【7gyy】教大家设置一个类似手机的锁屏界面
  13. jQuery实现雪花飘落效果
  14. QQ会员注册完整代码
  15. 力扣题目归类,顺序刷题不再难
  16. Vue2.0 饿了么报错: Unexpected side effect in lis tShow computed property
  17. NIST 网络安全框架导读
  18. Zblog博客怎么实现QQ登陆?
  19. 天津市铁道职业技术学院计算机专业,天津铁道职业技术学院专业介绍
  20. 排列组合思维导图_思维模型10 - 排列组合是什么?

热门文章

  1. 使用Python操作Excel图表之 为最后一个数据点添加数据标签
  2. 中文分词算法——基于统计的分词
  3. python-request(基本用法)
  4. idea连接oracle可插拔数据库报ORA-12505
  5. ROS安装/// rosdep update/the read operation is timed out
  6. 离线数仓搭建_11_DWD层用户行为日志创建
  7. vim 命令插入、删除、查询、替换操作。
  8. MySQL-语句块-循环语句
  9. 名片管理系统python详解_详解Python做一个名片管理系统
  10. mos管的rc吸收电路计算_一种反激式开关电源中MOS管的RC吸收电路的制作方法