关于求模和求余

摘要:
p=269规定“aMODb”的b不能为负数分三种情况来处理amodb计算a和b均为正整数当a和b均为正整数时,amodb实为求余运算。即两个整数除以同一整数,余数相同,则两数同余。既然我们不知道如何直接对负数求模,那找到这个负数同余的正整数便可以了。写成代码就是:123456789101112131415#includeusingnamespacestd;intmain(){inta=-1;intb=26;intc=a%b;if(c˂0){cout˂˂(c+b)˂˂endl;}else{cout˂˂c˂˂endl;}}分数求模最后这个最麻烦点,是分数求模运算。要计算a^{-1}modb,也称为对b求a的反模。为了对分数求模,我们需要使用欧几里德扩展算法。

求余:

取整除后的余数。例如:

10 MOD 4=2; -17 MOD 4=-1; -3 MOD 4=-3; 4 MOD (-3)=1; -4 MOD 3=-1

如果有a MOD b是异号,那么得出的结果符号与a相同;当然了,a MOD b就相当于a-(a DIV B ) *b的运算。例如:

13 MOD 4=13-(13 DIV 4)*4=13-12=1

求模:

转载:http://www.allopopo.cn/?p=269

规定“a MOD b”的b不能为负数

分三种情况来处理 a mod b 计算

a 和 b 均为正整数

当 a 和 b 均为正整数时,a mod b 实为求余运算。

(i)当a>b时,不断从a中减去b,直到出现了一个小于b的非负数。

例如: 8 MOD 3=2

(ii)当a<b时,结果为a。如:

3 MOD 8=3

a 为负整数

当 a 为负整数时,稍微麻烦点。例如 -1 mod 26,写个程序测试一下:

1
2
3
4
5
6
7
8
9
10
#include <iostream>
usingnamespacestd;
intmain(){
inta = -1;
intb = 26;
intc = a % b;
cout << c << endl;
}

得到的结果是 -1,但是实际运算结果应当为 25。用 Java 写了个程序,运算结果也是一样的,也是 -1。这是因为无论是 C++ 还是 Java 都不处理同余的情况。即两个整数除以同一整数,余数相同,则两数同余。既然我们不知道如何直接对负数求模,那找到这个负数同余的正整数便可以了。

要计算 c = a mod b,其中 a 为负数,要找得与 a 同余的正整数,只需要再在 a 的基础上,再 + b 即可。写成代码就是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
usingnamespacestd;
intmain(){
inta = -1;
intb = 26;
intc = a % b;
if(c < 0){
cout << (c + b) << endl;
}else{
cout << c << endl;
}
}
分数求模

最后这个最麻烦点,是分数求模运算。因为服务器不支持 LaTeX,所以只能用比较粗糙的数学书写格式,^{} 用于上标,而 _{} 则是下标。

要计算 a^{-1} mod b,也称为对 b 求 a 的反模。我们需要寻找 c,使得 c * a mod b = 1。例如 1/4 mod 9 = 7,因为 7 * 4 = 28,28 mod 9 = 1。并且只有当 a 和 b 的最大公约数为 1 时,此反模才存在。

为了对分数求模,我们需要使用欧几里德扩展算法。逐步推进,从步骤 0 开始,在步骤 i 求得的商标记为 Q_{i}。除以以外,每个步骤还需要计算一个临时的量,标记为 Y_{i},Y_{0} 和 Y_{1} 已经给出,分别是 0 和 1。再往后的计算当中,每次循环,更新 Y_{i} = Y_{i-2}- Y_{i-1} * Q_{i-2} mod b。循环从 b 除以 a 开始:

假设我们要对 26 求 15 的反模,也就是 1/15 mod 26。

步骤 026 = 01 * 15 + 11Y_{0} = 0
步骤 115 = 01 * 11 + 04Y_{1} = 1
步骤 211 = 02 * 04 + 03Y_{2} = Y_{0} – Y_{1} * Q_{0} mod 26 = 00 – 01 * 01 mod 26 = 25
步骤 304 = 01 * 03 + 01Y_{3} = Y_{1} – Y_{2} * Q_{1} mod 26 = 01 – 25 * 01 mod 26 = 02
步骤 403 = 03 * 01 + 00Y_{4} = Y_{2} – Y_{3} * Q_{2} mod 26 = 25 – 02 * 02 mod 26 = 21
Y_{5} = Y_{3} – Y_{4} * Q_{3} mod 26 = 02 – 21 * 01 mod 26 = 07

如果最后一个非零余数出现在第 k 步骤,且余数为 1,则反模存在,且为 Y_{k+2}。在我们这个例子当中,最后一个非零余数出现在步骤 3,且此余数为 1,所以对 26 求 15 的反模,应当为 Y_{5} = 7。由此,最后得出 1/15 mod 26 = 7。

最后列出分数求模的算法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 求 a^{-1} mod b
Y1 := 0
Y2 := 1
B := b
A := a
Q := 最近一个小于或等于 B / A 的整数
R := B - Q * A
当 R > 0 循环
Temp := Y1 - Y2 * Q
如果 Temp 大于等于 0 则
Temp := Temp mod b
否则
Temp := b - ((-Temp) mod b)
Y1 := Y2
Y2 := Temp
A := B
B := R
Q := 最近一个小于或等于 B / A 的整数
R := B - Q * A
循环末
如果 bo 不等于 1 则 b 不具有针对 n 的反模。
否则返回 Y2。

翻译成 Java 方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
publicstaticinteuclideEtendu(inta, intp)
{
intn0 = p;
intb0 = a;
intt0 = 0;
intt=1;
intq = n0/b0;
intr=n0-q*b0;
inttemp = 0;
System.out.println("=>Calculation of "+ a + "^-1 mod "+ p + " using Extended Euclidean Algorithm");
while(r>0)
{
temp = t0-q*t;
if(temp>=0){
temp = temp % p;
}else{
temp = p-(-temp % p);
}
t0=t;
t=temp;
n0=b0;
b0=r;
q=(n0/b0);
r=n0-q*b0;
}
if(b0!=1){
System.out.println(a + " doesn't have inverse modulo of "+ p);
t=-1;
}
returnt;
}

免责声明:文章转载自《关于求模和求余》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇跟我学机器视觉HALCON学习例程中文详解开关引脚测量uboot启动后在内存中运行裸机程序hello下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

MATLAB调用C程序、调试和LDPC译码

MATLAB是一个很好用的工具。利用MATLAB脚本进行科学计算也特别方便快捷。但是代码存在较多循环时,MATLAB运行速度极慢。如果不想放弃MATLAB中大量方便使用的库,又希望代码能迅速快捷的运行,可以考虑将循环较多的功能采用C编写,MATLAB调用。本文将概述这一过程。虽然本文以LDPC译码算法为例,但不懂该算法不影响本文阅读。 1. 起因    ...

win32-使用FillRect绘制具有渐变颜色的客户区域背景

void OnEraseBkGnd(HWND hwnd) { /* Vars */ HDC dc; /* Standard Device Context; used to do the painting */ /* rect = Client Rect of the window; Temp = Temparory rec...

shell高级-----创建函数

基本脚本函数 1、创建函数 有两种格式可以用来在bash shell脚本中创建函数。第一种采用关键字function。后跟分配给该代码的函数名。 function name { commands } name属性定义了赋予函数唯一的名称。脚本中定义的每个函数都必须有一个唯一的名称。commands是构成函数的一条或多条bash...

假设检验的Python实现

结合假设检验的理论知识,本文使用Python对实际数据进行假设检验。 导入测试数据 从线上下载测试数据文件,数据链接:https://pan.baidu.com/s/1t4SKF6U2yyjT365FaE692A* 数据字段说明: gender:性别,1为男性,2为女性 Temperature:体温 HeartRate:心率 下载后,使用pandas的re...

Java对文件的16进制读取和操作

大家可以参考一下源代码的相关部分注释,然后写出自己的16进制处理程序。有几个重点地方:16进制字符串-》10进制数 int input = Integer.parseInt("Str", 16)10进制整数-》16进制字符串 String hex = Integer.toHexString(int)文件读取方法 作为2进制文件直接读取,一个byte为单位的...

ora-01652无法通过128(在temp表空间中)扩展temp段

有两种错误:1.数据表空间不足 2.临时表空间不足 有两种原因:一是临时表空间空间太小,二是不能自动扩展。 分析过程:    既然是temp表空间有问题,那当然就要从temp表空间说起啦。首先要说明的是temp表空间的作用,temp表空间主要是用作需要排序的操作。    1.临时表空间 是用于在进行排序操作(如大型查询,创建索引和联合查询期间存储临时数据)...