當前位置:首頁 » 編程語言 » 模二加法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';
}