当前位置:首页 » 编程语言 » 模二加法c语言
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

模二加法c语言

发布时间: 2022-08-11 18:29:54

c语言中怎么进行二进制数的求模运算(和求余不同哦)

你可以索性写为x^2+(-x)+1或x^2+(x*(-1)^3)+1

Ⅱ C语言实现两个数的加法,这两个数可能非常大,有一千位或一万位等,用正常的加法超过了double类型的范围。

void Add(char *str1, char *str2, char *str3)
{// str3 = str1 + str2;
int i, j, i1, i2, tmp, carry;
int len1 = strlen(str1), len2 = strlen(str2);
char ch;
i1 = len1-1; i2 = len2-1;
j = carry = 0;
for( ; i1 >= 0 && i2 >= 0; ++j, --i1, --i2 ){
tmp = str1[i1]-'0'+str2[i2]-'0'+carry;
carry = tmp/10;
str3[j] = tmp%10+'0';
}
while( i1 >= 0 ){
tmp = str1[i1--]-'0'+carry;
carry = tmp/10;
str3[j++] = tmp%10+'0';
}
while( i2 >= 0 ){
tmp = str2[i2--]-'0'+carry;
carry = tmp/10;
str3[j++] = tmp%10+'0';
}
if( carry ) str3[j++] = carry+'0';
str3[j] = '\0';
for( i=0, --j; i < j; ++i, --j ){
ch = str3[i]; str3[i] = str3[j]; str3[j] = ch;
}
}
是数组实现的, 把str1 和str2是你要相加的两个数, str3是用来放加后的结果
注意:你读入时,用数组读入 ,且这个函数只能处理整数,小数不行

Ⅲ 在C语言中,0%2=

在C语言中,0%2= 0 。

在C语言中,这是一个取模运算,定义如下:

给定一个正整数p,任意一个整数n,一定存在等式 :

n = kp + r ;

其中 k、r 是整数,且 0 ≤ r < p,则称 k 为 n 除以 p 的商,r 为 n 除以 p 的余数。

对于正整数 p 和整数 a,b,定义如下运算:

取模运算:a % p(或a mod p),表示a除以p的余数。

模p加法: ,其结果是a+b算术和除以p的余数。

模p减法: ,其结果是a-b算术差除以p的余数。

模p乘法: ,其结果是 a * b算术乘法除以p的余数。

说明:

1. 同余式:正整数a,b对p取模,它们的余数相同,记做 或者a ≡ b (mod p)。

2. n % p 得到结果的正负由被除数n决定,与p无关。例如:7%4 = 3, -7%4 = -3, 7%-4 = 3, -7%-4 = -3。

(3)模二加法c语言扩展阅读:

1、运算规则

模运算与基本四则运算有些相似,但是除法例外。其规则如下:

(a + b) % p = (a % p + b % p) % p

(a - b) % p = (a % p - b % p) % p

(a * b) % p = (a % p * b % p) % p

a ^ b % p = ((a % p)^b) % p

结合律:

((a+b) % p + c) % p = (a + (b+c) % p) % p

((a*b) % p * c)% p = (a * (b*c) % p) % p

交换律:

(a + b) % p = (b+a) % p

(a * b) % p = (b * a) % p

分配律:

(a+b) % p = ( a % p + b % p ) % p

((a +b)% p * c) % p = ((a * c) % p + (b * c) % p) % p

2、重要定理

若a≡b (% p),则对于任意的c,都有(a + c) ≡ (b + c) (%p);

若a≡b (% p),则对于任意的c,都有(a * c) ≡ (b * c) (%p);

若a≡b (% p),c≡d (% p),则 (a + c) ≡ (b + d) (%p),(a - c) ≡ (b - d) (%p),(a * c) ≡ (b * d) (%p);

Ⅳ 在C语言中,要求运算数必须是整型的运算符是( )

选择D。

%是求余运算符,也叫模除运算符,用于求余数。%要求两个操作数均为整数(或可以隐式转换成整数的类型)。

标准规定:

1、如果%左边的操作数为负数时,则模除的结果为负数或者0,

2、如果%左边的操作数为正数时,则模除的结构为正数或者0。

测试代码:

(4)模二加法c语言扩展阅读:

关于余数,正整数 p 和整数 a,b,定义如下运算:

1、取模运算:a % p(或a mod p),表示a除以p的余数。

2、模p加法: ,其结果是a+b算术和除以p的余数。

3、模p减法: ,其结果是a-b算术差除以p的余数。

4、模p乘法: ,其结果是 a * b算术乘法除以p的余数。

说明:

1、同余式:正整数a,b对p取模,它们的余数相同,记做 或者a ≡ b (mod p)。

2、n % p 得到结果的正负由被除数n决定,与p无关。例如:7%4 = 3, -7%4 = -3, 7%-4 = 3, -7%-4 = -3。

Ⅳ c语言运算符号的表示方法

1
算术运算符
用于各类数值运算。包括加(+)、减(-)、乘(*)、除(/)、求余(或称模运算,%)、自增(++)、自减(--)共七种。
2.关系运算符
用于比较运算。包括大于(>)、小于(<)、等于(==)、
大于等于(>=)
、小于等于(<=)和不等于(!=)六种。
3.逻辑运算符
用于逻辑运算。包括与(&&)、或(||)、非(!)三种。
4.位操作运算符
参与运算的量,按二进制位进行运算。包括位与(&)、位或(|)、位非(~)、位异或(^)、左移(<<)、右移(>>)六种。
5.赋值运算符
用于赋值运算,分为简单赋值(=)、复合算术赋值(+=,-=,*=,/=,%=)和复合位运算赋值(&=,|=,^=,>>=,<<=)三类共十一种。
6.条件运算符
这是一个三目运算符,用于条件求值(?:)。
7.逗号运算符
用于把若干表达式组合成一个表达式(,)。
8.指针运算符
用于取内容(*)和取地址(&)二种运算。
9.求字节数运算符
用于计算数据类型所占的字节数(sizeof)。
10.特殊运算符
有括号(),下标[],成员(→,.)等几种。
优先级1级
结合方向
左结合(自左至右)
(
)
圆括号
[
]下标运算符
->
指向结构体成员运算符
.
结构体成员运算符(请注意它是一个实心圆点)
优先级2级
结合方向
右结合(自右至左)单目运算符
!
逻辑非运算符
~
按位取反运算符
++
自增运算符
--
自减运算符
-负号运算符
(类型)
类型转换运算符
*
指针运算符
&
地址与运算符
sizeof
长度运算符
优先级3级
结合方向
左结合
双目运算符
*
乘法运算符
/
除法运算符
%
取余运算符
优先级4级
结合方向
左结合
双目运算符
+
加法运算符
-
减法运算符
优先级5级
结合方向
左结合
双目运算符
<<
左移运算符
>>
右移运算符
优先级6级
结合方向
左结合
双目运算符
<、<=、>、>=
关系运算符
优先级7级
结合方向
左结合
双目运算符
==
等于运算符
(判断)
!=
不等于运算符(判断)
优先级8级
结合方向
左结合
双目运算符
&
按位与运算符
优先级9级
结合方向
左结合
双目运算符
^
按位异或运算符
优先级10级
结合方向
左结合
双目运算符
|
按位或运算符
举例:0xfe|0xef
即为1111
1110
与1110
1111按位或运算则答案为:1111
1111
即0xff。
优先级11级
结合方向
左结合
双目运算符
&&
逻辑与运算符
优先级12级
结合方向
左结合
双目运算符
||
逻辑或运算符
优先级13级
结合方向
右结合
三目运算符
?
:
条件运算符
优先级14级
结合方向
右结合
双目运算符
=
赋值运算符
+
=
加后赋值运算符
如s+=1表示s=s+1
-
=
减后赋值运算符
如s-=1表示s=s-1
*
=
乘后赋值运算符
/
=
除后赋值运算符
%
=
取模后赋值运算符
<
<=
左移后赋值运算符
>>=右移后赋值运算符
&=
按位与后赋值运算符
^=按位异或后赋值运算符
|=
按位或后赋值运算符
优先级15级
结合方向
左结合

逗号运算符

Ⅵ 运算符和表达式之间有什么联系

2.6 运算符
C语言的内部运算符很丰富,运算符是告诉编译程序执行特定算术或逻辑操作的符号。C语言有三大运算符:算术、关系与逻辑、位操作。另外, C还有一些特殊的运算符,用于完成一些特殊的任务。

2.6.1 算术运算符
表2 - 5列出了C语言中允许的算术运算符。在C语言中,运算符“ +”、“-”、“*”和“ /”的用法与大多数计算机语言的相同,几乎可用于所有C语言内定义的数据类型。当“ /”被用于整数或字符时,结果取整。例如,在整数除法中, 1 0 / 3 = 3。
一元减法的实际效果等于用- 1乘单个操作数,即任何数值前放置减号将改变其符号。模运算符“%”在C语言中也同它在其它语言中的用法相同。切记,模运算取整数除法的余数,所以“%”不能用于float和double类型。

表2-5 算术运算符
运算符 作用 运算符 作用
- 减法,也是一元减法 % 模运算
+ 加法 -- 自减(减1)
* 乘法 ++ 自增(增1)
/ 除法

下面是说明%用法的程序段。
int x,y;
x = 10;
y = 3;
printf("%d",x/y); /* 显示3 */
printf("%d",x%y) ; /* 显示1 ,整数除法的余数* /
x = 1 ;
y = 2 ;
printf("%d,%d",x/y,x%y) ; /* 显示0,1 */
最后一行打印一个0和一个1,因为1 / 2整除时为0,余数为1,故1 % 2取余数1。

2.6.2 自增和自减
C语言中有两个很有用的运算符,通常在其它计算机语言中是找不到它们的—自增和自减运算符, + +和- -。运算符“ + +”是操作数加1,而“- -”是操作数减1,换句话说:x = x + 1 ; 同+ + x ; x = x - 1 ; 同- - x ;
自增和自减运算符可用在操作数之前,也可放在其后,例如: x = x + 1;可写成+ + x;或x + +;但在表达式中这两种用法是有区别的。自增或自减运算符在操作数之前, C语言在引用操作数之前就先执行加1或减1操作;运算符在操作数之后, C语言就先引用操作数的值,而后再进行加1或减1操作。请看下例:
x = 1 0;
y = ++x;
此时,y = 11。如果程序改为:
x = 10 ;
y = x++ ;
则y = 10。在这两种情况下, x都被置为11,但区别在于设置的时刻,这种对自增和自减发生时刻的控制是非常有用的。
在大多数C编译程序中,为自增和自减操作生成的程序代码比等价的赋值语句生成的代码要快得多,所以尽可能采用加1或减1运算符是一种好的选择。
下面是算术运算符的优先级:
最高 ++、--
-(一元减)
*、/、%
最低 +、-
编译程序对同级运算符按从左到右的顺序进行计算。当然,括号可改变计算顺序。C语言处理括号的方法与几乎所有的计算机语言相同:强迫某个运算或某组运算的优先级升高。

2.6.3 关系和逻辑运算符
关系运算符中的“关系”二字指的是一个值与另一个值之间的关系,逻辑运算符中的“逻辑”二字指的是连接关系的方式。因为关系和逻辑运算符常在一起使用,所以将它们放在一起讨论。
关系和逻辑运算符概念中的关键是True(真)和Flase(假)。C语言中,非0为True,0为Flase。使用关系或逻辑运算符的表达式对Flase和Ture分别返回值0或1 (见表2 - 6 )。

表2-6 关系和逻辑运算符
关系运算符 含义 关系运算符 含义
> 大于 <= 小于或等于
>= 大于等于 == 等于
< 小于 != 不等于

逻辑运算符 含义
&& 与
|| 或
! 非

表2 - 6给出于关系和逻辑运算符,下面用1和0给出逻辑真值表。
关系和逻辑运算符的优先级比算术运算符低,即像表达式10>1+12的计算可以假定是对表
达式10>( 1 + 12)的计算,当然,该表达式的结果为Flase。
在一个表达式中允许运算的组合。例如:
10>5&&!(10<9)||3<=4
p q p&&q p||q !p
0 0 0 0 1
0 1 0 1 1
1 0 0 1 0
1 1 1 1 0

这一表达式的结果为True。
下表给出了关系和逻辑运算符的相对优先级:
最高 !
>= <=
== !=
&&
最低 ||
同算术表达式一样,在关系或逻辑表达式中也使用括号来修改原计算顺序。
切记,所有关系和逻辑表达式产生的结果不是0就是1,所以下面的程序段不仅正确而且将在屏幕上打印数值1。
int x;
x = 100;
printf("%d",x>10);

2.6.4 位操作符
与其它语言不同,C语言支持全部的位操作符( Bitwise Operators)。因为C语言的设计目的是取代汇编语言,所以它必须支持汇编语言所具有的运算能力。位操作是对字节或字中的位(bit)进行测试、置位或移位处理,这里字节或字是针对C标准中的char和int数据类型而言的。位操作不能用于float、double、long double、void或其它复杂类型。表

2 - 7给出了位操作
的操作符。位操作中的AND、OR和NOT(1的补码)的真值表与逻辑运算等价,唯一不同的是位操作是逐位进行运算的。

表2-7 位操作符
操作符 含义 操作符 含义
& 与(AND) ~ 1的补(NOT)
| 或(OR) >> 右移
^ 异或(XOR) << 左移

下面是异或的真值表。
表2-8 异或的真值表
p q p^q
0 0 0
1 0 1
1 1 0
0 1 1

如表2 - 8所示,当且仅当一个操作数为True时,异或的输出为True,否则为Flase。
位操作通常用于设备驱动程序,例如调制解调器程序、磁盘文件管理程序和打印机驱动程序。这是因为位操作可屏蔽掉某些位,如奇偶校验位(奇偶校验位用于确保字节中的其它位不会发生错误通常奇偶校验位是字节的最高位)。
通常我们可把位操作A N D作为关闭位的手段,这就是说两个操作数中任一为0的位,其结果中对应位置为0。例如,下面的函数通过调用函数read_modem( ),从调制解调器端口读入一个字符,并将奇偶校验位置成0。

[例2 - 4 ]
Char get_char_from_modem()
{
char ch;
ch=read_modem(); /*从调制解调器端口中得到一个字符* /
return(ch&127);
}
字节的位8是奇偶位,将该字节与一个位1到位7为1、位8为0的字节进行与操作,可将该字节的奇偶校验位置成0。表达式ch&127正是将ch中每一位同127数字的对应位进行与操作,结果ch的位8被置成了0。在下面的例子中,假定c h接收到字符"A"并且奇偶位已经被置位。
奇偶位

110000001 内容为‘A’的c h,其中奇偶校验位为1
011111111 二进制的127执行与操作
& 与操作
-----------
=010000001 去掉奇偶校验的‘A’

位操作OR与AND操作相反,可用来置位。任一操作数中为1的位将结果的对应位置1。如下所示,128|3的情况是:
1000000 128的二进制
0000011 3的二进制
| 或操作
----------
=1000011 结果

异或操作通常缩写为XOR,当且仅当做比较的两位不同时,才将结果的对应位置位。如下所示,异或操作127 ^ 12 0的情况是:
01111111 127 的二进制
01111000 120 的二进制
^ 异或操作
---------
=00000111 结果
一般来说,位的AND、OR和XOR操作通过对操作数运算,直接对结果变量的每一位分别处理。正是因为这一原因(还有其它一些原因),位操作通常不像关系和逻辑运算符那样用在条件语句中,我们可以用例子说明这一点:假定X = 7,那么x && 8为Ture( 1 ) ,而x & 8却为Flase( 0 )。
记住,关系和逻辑操作符结果不是0就是1。而相似的位操作通过相应处理,结果可为任意值。换言之,位操作可以有0或1以外的其它值,而逻辑运算符的计算结果总是0或1。
移位操作符>>和<<将变量的各位按要求向或向左移动。右移语句通常形式是:
variable >>右移位数
左移语句是:
variable << 左移位数
当某位从一端移出时,另一端移入0(某些计算机是送1,详细内容请查阅相应C编译程序用户手册)。切记:移位不同于循环,从一端移出的位并不送回到另一端去,移去的位永远丢失了,同时在另一端补0。
移位操作可对外部设备(如D/A转换器)的输入和状态信息进行译码,移位操作还可用于整数的快速乘除运算。如表2 - 9所示(假定移位时补0),左移一位等效于乘2,而右移一位等效于除以2。

表2-9 用移位操作进行乘和除
字符x 每个语句执行后的x x的值
x=7 00000111 7
x<<1 00001110 14
x<<3 01110000 112
x<<2 11000000 192
x>>1 01100000 96
x>>2 00011000 24

每左移一位乘2,注意x < < 2后,原x的信息已经丢失了,因为一位已经从一端出,每右移一位相当于被2除,注意,乘后再除时,除操作并不带回乘法时已经丢掉的高位。
反码操作符为~。~的作用是将特定变量的各位状态取反,即将所有的1位置成0,所有的0位置成1。
位操作符经常用在加密程序中,例如,若想生成一个不可读磁盘文件时,可以在文件上做一些位操作。最简单的方法是用下述方法,通过1的反码运算,将每个字节的每一位取反。
原字节 00101100
第一次取反码 11010011
第二次取反码 00101100
注意,对同一行进行连续的两次求反,总是得到原来的数字,所以第一次求反表示了字节的编码,第二次求反进行译码又得到了原来的值。
可以用下面的函数encode( )对字符进行编码。

[例2 - 5 ]
char encode(ch)
char ch;
{
return (~ch);
}

2.6.5 ?操作符
C语言提供了一个可以代替某些if - then - else语句的简便易用的操作符?。该操作符是三元的,其一般形式为:
EXP1? EXE2: EXP3
EXP1,EXP2和EXP3是表达式,注意冒号的用法和位置。
操作符“?”作用是这样的,在计算EXP1之后,如果数值为True,则计算EXP2,并将结果作为整个表达式的数值;如果E XP1的值为Flase,则计算EXP3,并以它的结果作为整个表达式的值,请看下例:
x = 10;
y = x> 9? 100: 200;
例中,赋给y的数值是100,如果x被赋给比9小的值,y的值将为200,若用if - else语句改写,有下面的等价程序:
x = 10;
if(x>9) y=100;
else y=200;
有关C语言中的其它条件语句将在第3章进行讨论。

2.6.6 逗号操作符
作为一个操作符,逗号把几个表达式串在一起。逗号操作符的左侧总是作为void(无值),这意味着其右边表达式的值变为以逗号分开的整个表达式的值。例如:
x = ( y = 3 , y + 1 ) ;
这行将3赋给y,然后将4赋给x,因为逗号操作符的优先级比赋值操作符优先级低,所以必须使用括号。
实际上,逗号表示操作顺序。当它在赋值语句右边使用时,所赋的值是逗号分隔开的表中最后那个表达式的值。例如,
y = 10;
x = (y = y - 5 , 2 5 / y ) ;
执行后,x的值是5,因为y的起始值是1 0,减去5之后结果再除以2 5,得到最终结果。
在某种意义上可以认为,逗号操作符和标准英语的and是同义词。

2.6.7 关于优先级的小结
表2 - 1 0列出了C语言所有操作符的优先级,其中包括将在本书后面讨论的某些操作符。注意,所有操作符(除一元操作符和?之外)都是左结合的。一元操作符( *,&和-)及操作符“?”则为右结合。
表2-10 C语言操作符的优先级
最高级 ()[] →
!~ ++ -- -(type) * & sizeof
* / %
+ -
<< >>
<= >=
== !=
& ^ |
&&
||
?
= += -= *= /=
最低级,
2.7 表达式
表达式由运算符、常量及变量构成。C语言的表达式基本遵循一般代数规则,有几点却是与C语言紧密相关的,以下将分别加以讨论。

2.7.1 表达式中的类型转换
混合于同一表达式中的不同类型常量及变量,应均变换为同一类型的量。C语言的编译程序将所有操作数变换为与最大类型操作数同类型。变换以一次一操作的方式进行。具体规则如下:

1 ) 所有char及short int 型量转为int型,所有float转换为double。
2) 如操作数对中一个为long double ,另一个转换为long double。① 要不然,一个为double,另一个转为doub le。② 要不然,一个为long,另一个转为long。③ 要不然,一个为unsigned,另一个转为unsigned。
一旦运用以上规则。每一对操作数均变为同类型。注意,规则2 )有几种必须依次应用的条件。
图2 - 1示出了类型转换。首先, char ch转换成int,且floatf 转换成double;然后ch /i的结果转换成doubl e,因为f * d是double;最后由于这次两个操作数都是double,所以结果也是double。.

2.7.2 构成符cast
可以通过称为cast的构成符强迫一表达式变为特定类型。其一般形式为:
(type)expression
( type)是标准C语言中的一个数据类型。例如,为确保表达式x / 2的结果具有类型float,可写为:
(float)x / 2
通常认为cast是操作符。作为操作符, cast是一元的,并且同其它一元操作符优先级相同。
虽然cast在程序中用得不多,但有时它的使用的确很有价值。例如,假设希望用一整数控制循环,但在执行计算时又要有小数部分。

[例2 - 6 ]
main()
{
int i;
for(i+1;i<=100;++i)
printf("%d/2 is :%f",i,(float)i/2);
}
若没有cast( float),就仅执行一次整数除;有了cast就可保证在屏幕上显示答案的小数部分。

2.7.3 空格与括号
为了增加可读性,可以随意在表达式中插入tab和空格符。例如,下面两个表达式是相同的。
x = 10 / y *( 127 / x );
x = 10 / y *( 127 / x );
冗余的括号并不导致错误或减慢表达式的执行速度。我们鼓励使用括号,它可使执行顺序更清楚一些。例如,下面两个表达式中哪个更易读一些呢?
x = y / 2 - 34 * temp & 127;
x = ( y / 2 ) - ( ( 34 * temp) & 127);

2.7.4 C语言中的简写形式
C语言提供了某些赋值语句的简写形式。例如语句:
x = x + 10;
在C语言中简写形式是:
x + = 10;
这组操作符对+ =通知编译程序将X + 1 0的值赋予X。这一简写形式适于C语言的所有二元操作符(需两个操作数的操作符)。在C语言中,variable=variable1 operator expression;与variable1 operator=expression相同。

请看另一个例子:
x = x - 1 0 0 ;
其等价语句是
x - = 100;
简写形式广泛应用于专业C语言程序中,希望读者能熟悉它。

Ⅶ &运算符是如何运算的

按位与运算符"&"是双目运算符是参与运算的两数各对应的二进位相与。

按位与"&"功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1 ,否则为0。参与运算的数以补码方式出现。

例如:9&5可写算式如下: 00001001 (9的二进制补码)&00000101 (5的二进制补码) 00000001 (1的二进制补码)可见9&5=1。 按位与运算通常用来对某些位清0或保留某些位。

(7)模二加法c语言扩展阅读:

相关的位运算符:

1、按位或运算“|”:

按位或运算符“|”是双目运算符。 其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。

2、按位异或运算“^”:

按位异或运算符“^”是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。参与运算数仍以补码出现。

Ⅷ C语言取余的原理是怎么回事 比如 int X,Y X-X/Y*Y=x%y

取余实际上就是模运算

基本理论
基本概念:
给定一个正整数p,任意一个整数n,一定存在等式 n = kp + r ;
其中k、r是整数,且 0 ≤ r < p,称呼k为n除以p的商,r为n除以p的余数。
对于正整数p和整数a,b,定义如下运算:
取模运算:a % p(或a mod p),表示a除以p的余数。
模p加法:(a + b) % p ,其结果是a+b算术和除以p的余数,也就是说,(a+b) = kp +r,则(a + b) % p = r。
模p减法:(a-b) % p ,其结果是a-b算术差除以p的余数。
模p乘法:(a * b) % p,其结果是 a * b算术乘法除以p的余数。
说明:
1. 同余式:正整数a,b对p取模,它们的余数相同,记做 a ≡ b % p或者a ≡ b (mod p)。
2. n % p得到结果的正负由被除数n决定,与p无关。例如:7%4 = 3, -7%4 = -3, 7%-4 = 3, -7%-4 = -3。
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->
基本性质
(1)若p|(a-b),则a≡b (% p)。例如 11 ≡ 4 (% 7), 18 ≡ 4(% 7)
(2)(a % p)=(b % p)意味a≡b (% p)
(3)对称性:a≡b (% p)等价于b≡a (% p)
(4)传递性:若a≡b (% p)且b≡c (% p) ,则a≡c (% p)
运算规则
模运算与基本四则运算有些相似,但是除法例外。其规则如下:
(a + b) % p = (a % p + b % p) % p (1)
(a - b) % p = (a % p - b % p) % p (2)
(a * b) % p = (a % p * b % p) % p (3)
ab % p = ((a % p)b) % p (4)
结合率: ((a+b) % p + c) % p = (a + (b+c) % p) % p (5)
((a*b) % p * c)% p = (a * (b*c) % p) % p (6)
交换率: (a + b) % p = (b+a) % p (7)
(a * b) % p = (b * a) % p (8)
分配率: ((a +b)% p * c) % p = ((a * c) % p + (b * c) % p) % p (9)
重要定理:若a≡b (% p),则对于任意的c,都有(a + c) ≡ (b + c) (%p);(10)
若a≡b (% p),则对于任意的c,都有(a * c) ≡ (b * c) (%p);(11)
若a≡b (% p),c≡d (% p),则 (a + c) ≡ (b + d) (%p),(a - c) ≡ (b - d) (%p),
(a * c) ≡ (b * d) (%p),(a / c) ≡ (b / d) (%p); (12)
若a≡b (% p),则对于任意的c,都有ac≡ bc (%p); (13)
编辑本段
基本应用

1.判别奇偶数
奇偶数的判别是模运算最基本的应用,也非常简单。易知一个整数n对2取模,如果余数为0,则表示n为偶数,否则n为奇数。
C++实现功能函数:
/*
函数名:IsEven
函数功能:判别整数n的奇偶性。能被2整除为偶数,否则为奇数
输入值:int n,整数n
返回值:bool,若整数n是偶数,返回true,否则返回false
*/
bool IsEven(int n)
{
return (n % 2 == 0);
}
2.判别素数
一个数,如果只有1和它本身两个因数,这样的数叫做质数(或素数)。例如 2,3,5,7 是质数,而 4,6,8,9 则不是,后者称为合成数或合数。
判断某个自然数是否是素数最常用的方法就是试除法:用比该自然数的平方根小的正整数去除这个自然数,若该自然数能被整除,则说明其非素数。
C++实现功能函数:
/*
函数名:IsPrime
函数功能:判别自然数n是否为素数。
输入值:int n,自然数n
返回值:bool,若自然数n是素数,返回true,否则返回false
*/
bool IsPrime(unsigned int n)
{
unsigned maxFactor = sqrt(n); //n的最大因子
for (unsigned int i=2; i<=maxFactor; i++)
{
if (n % i == 0) //n能被i整除,则说明n非素数
{
return false;
}
}
return true;
}
3. 最大公约数
求最大公约数最常见的方法是欧几里德算法(又称辗转相除法),其计算原理依赖于定理:gcd(a,b) = gcd(b,a mod b)
证明:a可以表示成a = kb + r,则r = a mod b
假设d是a,b的一个公约数,则有d|a, d|b,而r = a - kb,因此d|r
因此d是(b,a mod b)的公约数
假设d 是(b,a mod b)的公约数,则d | b , d |r ,但是a = kb +r
因此d也是(a,b)的公约数
因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证。
C++实现功能函数:
/*
函数功能:利用欧几里德算法,采用递归方式,求两个自然数的最大公约数
函数名:Gcd
输入值:unsigned int a,自然数a
unsigned int b,自然数b
返回值:unsigned int,两个自然数的最大公约数
*/
unsigned int Gcd(unsigned int a, unsigned int b)
{
if (b == 0)
return a;
return Gcd(b, a % b);
}
/*
函数功能:利用欧几里德算法,采用迭代方式,求两个自然数的最大公约数 函数名:Gcd
输入值:unsigned int a,自然数a
unsigned int b,自然数b
返回值:unsigned int,两个自然数的最大公约数
*/
unsigned int Gcd(unsigned int a, unsigned int b)
{
unsigned int temp;
while (b != 0)
{
temp = a % b;
a = b;
b = temp;
}
return a;
}
4.模幂运算
利用模运算的运算规则,我们可以使某些计算得到简化。例如,我们想知道3333^5555的末位是什么。很明显不可能直接把3333^5555的结果计算出来,那样太大了。但我们想要确定的是3333^5555(%10),所以问题就简化了。
根据运算规则(4)ab % p = ((a % p)b) % p ,我们知道3333^5555(%10)= 3^5555(%10)。由于3^4 = 81,所以3^4(%10)= 1。
根据运算规则(3) (a * b) % p = (a % p * b % p) % p ,由于5555 = 4 * 1388 + 3,我们得到3^5555(%10)=(3^(4*1388) * 3^3)(%10)=((3^(4*1388)(%10)* 3^3(%10))(%10)
=(1 * 7)(%10)= 7。
计算完毕。
利用这些规则我们可以有效地计算X^N(% P)。简单的算法是将result初始化为1,然后重复将result乘以X,每次乘法之后应用%运算符(这样使得result的值变小,以免溢出),执行N次相乘后,result就是我们要找的答案。
这样对于较小的N值来说,实现是合理的,但是当N的值很大时,需要计算很长时间,是不切实际的。下面的结论可以得到一种更好的算法。
如果N是偶数,那么X^N =(X*X)^[N/2];
如果N是奇数,那么X^N = X*X^(N-1) = X *(X*X)^[N/2];
其中[N]是指小于或等于N的最大整数。
C++实现功能函数:
/*
函数功能:利用模运算规则,采用递归方式,计算X^N(% P)
函数名:PowerMod
输入值:unsigned int x,底数x
unsigned int n,指数n
unsigned int p,模p
返回值:unsigned int,X^N(% P)的结果
*/
unsigned int PowerMod(unsigned int x, unsigned int n, unsigned int p)
{
if (n == 0)
{
return 1;
}
unsigned int temp = PowerMod((x * x)%p, n/2, p); //递归计算(X*X)^[N/2]
if ((n & 1) != 0) //判断n的奇偶性
{
temp = (temp * x) % p;
}
return temp;
}
5.《孙子问题(中国剩余定理)》
在我国古代算书《孙子算经》中有这样一个问题:
“今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?”意思是,“一个数除以3余2,除以5余3,除以7余2.求适合这个条件的最小数。”
这个问题称为“孙子问题”.关于孙子问题的一般解法,国际上称为“中国剩余定理”.
我国古代学者早就研究过这个问题。例如我国明朝数学家程大位在他着的《算法统宗》(1593年)中就用四句很通俗的口诀暗示了此题的解法:
三人同行七十稀,五树梅花甘一枝,七子团圆正半月,除百零五便得知。
"正半月"暗指15。"除百零五"的原意是,当所得的数比105大时,就105、105地往下减,使之小于105;这相当于用105去除,求出余数。
这四句口诀暗示的意思是:当除数分别是3、5、7时,用70乘以用3除的余数,用21乘以用5除的余数,用15乘以用7除的余数,然后把这三个乘积相加。加得的结果如果比105大,就除以105,所得的余数就是满足题目要求的最小正整数解。
根据剩余定理,我把此种解法推广到有n(n为自然数)个除数对应n个余数,求最小被除数的情况。输入n个除数(除数不能互相整除)和对应的余数,计算机将输出最小被除数。
C++实现功能函数:
/*
函数名:ResieTheorem
函数功能:运用剩余定理,解决推广了的孙子问题。通过给定n个除数(除数不能互相整除)和对应的余数,返回最小被除数
输入值:unsigned int devisor[],存储了n个除数的数组
unsigned int remainder[],存储了n个余数的数组
int length,数组的长度
返回值:unsigned int, 最小被除数
*/
unsigned int ResieTheorem(const unsigned int devisor[], const unsigned int remainder[], int length)
{
unsigned int proct = 1; //所有除数之乘积
for (int i=0; i<length; i++)//计算所有除数之乘积
{
proct *= devisor[i];
}
//公倍数数组,表示除该元素(除数)之外其他除数的公倍数
unsigned int *commonMultiple = new unsigned int(length);
for (int i=0; i<length; i++)//计算除该元素(除数)之外其他除数的公倍数
{
commonMultiple[i] = proct / devisor[i];
}
unsigned int dividend = 0; //被除数,就是函数要返回的值
for (int i=0; i<length; i++)//计算被除数,但此时得到的不是最小被除数
{
unsigned int tempMul = commonMultiple[i];
//按照剩余理论计算合适的公倍数,使得tempMul % devisor[i] == 1
while (tempMul % devisor[i] != 1)
{
tempMul += commonMultiple[i];
}
dividend += tempMul * remainder[i]; //用本除数得到的余数乘以其他除数的公倍数
}
delete []commonMultiple;
return (dividend % proct); //返回最小被除数
}
6. 凯撒密码
凯撒密码(caeser)是罗马扩张时期朱利斯o凯撒(Julius Caesar)创造的,用于加密通过信使传递的作战命令。
它将字母表中的字母移动一定位置而实现加密。注意26个字母循环使用,z的后面可以堪称是a。
例如,当密匙为k = 3,即向后移动3位时,若明文为”How are you!”,则密文为”Krz h btx!”。
凯撒密码的加密算法极其简单。其加密过程如下:
在这里,我们做此约定:明文记为m,密文记为c,加密变换记为E(key1,m)(其中key1为密钥),
解密变换记为D(key2,m)(key2为解密密钥)(在这里key1=key2,不妨记为key)。
凯撒密码的加密过程可记为如下一个变换:c≡m+key (mod n) (其中n为基本字符个数)
同样,解密过程可表示为:m≡c+key (mod n) (其中n为基本字符个数)
C++实现功能函数:
/*
函数功能:使用凯撒密码原理,对明文进行加密,返回密文 函数名:Encrypt
输入值:const char proclaimedInWriting[],存储了明文的字符串
char cryptograph[],用来存储密文的字符串
int keyey,加密密匙,正数表示后移,负数表示前移
返回值:无返回值,但是要将新的密文字符串返回
*/
void Encrypt(const char proclaimedInWriting[], char cryptograph[], int key)
{
const int NUM = 26; //字母个数
int len = strlen(proclaimedInWriting);
for (int i=0; i<len; i++)
{
if (proclaimedInWriting[i] >= 'a' && proclaimedInWriting[i] <= 'z')
{//明码是大写字母,则密码也为大写字母
cryptograph[i] = (proclaimedInWriting[i] - 'a' + key) % NUM + 'a';
}
else if (proclaimedInWriting[i] >= 'A' && proclaimedInWriting[i] <= 'Z')
{//明码是小写字母,则密码也为小写字母
cryptograph[i] = (proclaimedInWriting[i] - 'A' + key) % NUM + 'A';
}
else
{//明码不是字母,则密码与明码相同
cryptograph[i] = proclaimedInWriting[i];
}
}
cryptograph[len] = '\0';
}
/*
函数功能:使用凯撒密码原理,对密文进行解密,返回明文 函数名:Decode
输入值:char proclaimedInWriting[],用来存储明文的字符串
const char cryptograph[],存储了密文的字符串
int keyey,解密密匙,正数表示前移,负数表示后移(与加密相反)
返回值:无返回值,但是要将新的明文字符串返回
*/
void Decode(const char cryptograph[], char proclaimedInWriting[], int key)
{
const int NUM = 26; //字母个数
int len = strlen(cryptograph);
for (int i=0; i<len; i++)
{
if (cryptograph[i] >= 'a' && cryptograph[i] <= 'z')
{//密码是大写字母,则明码也为大写字母,为防止出现负数,转换时要加个NUM
proclaimedInWriting[i] = (cryptograph[i] - 'a' - key + NUM) % NUM + 'a';
}
else if (cryptograph[i] >= 'A' && cryptograph[i] <= 'Z')
{//密码是小写字母,则明码也为小写字母
proclaimedInWriting[i] = (cryptograph[i] - 'A' - key + NUM) % NUM + 'A';
}
else
{//密码不是字母,则明码与明密相同
proclaimedInWriting[i] = cryptograph[i];
}
}
proclaimedInWriting[len] = '\0';
}