某年的6月1日是星期日。那么,同一年的6月30日是星期幾?
星期是7
天一個循環。所以說,這一天是星期幾,7
天之后同樣也是星期幾。而6
月30
日是在6
月1
日的29
天之后:29 ÷ 7 = 4 ... 1
用29
除以7
,可以得出余數為1
。而6
月1
日那一天是星期日,那么,6
月30
日就是星期日的后一天,也就是星期一。
某年的3月,Wendy想制定一個實習計劃,它想知道當年的7月和11月有哪幾天是星期天。但月歷壞了,5月后面的幾頁看不到了。Wendy卻輕松找到了想要的日期,難道Wendy是天才喵?
不是,因為它知道,每一年的3
月1
日到3
月30
日,與11
月1
日到11
月30
日,在星期上面是完全相同的。同樣,4
月1
日到4
月30
日,與7
月1
日到7
月30
日,在星期上面也是完全相同的(31
日除外)?。
這到底是怎么一回事呀?
每一年過了3
月之后,在天數上,4
月、6
月、9
月、11
月都是30
天,而其他的月份都是31
天。
把3
月到10
月的天數相加,得出:31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 = 245
。
245 ÷ 7= 35
,用245
除以一周的天數7
天,就可以得出,3
月1
日~3
月30
日,與11
月1
日~11
月30
日,在星期上面是完全相同的。
同樣,把4
月到6
月的天數相加,得出:30 + 31 + 30 = 91
。
91 ÷ 7 = 13
,就可以得出,4
月1
日到4
月30
日,與7
月1
日到7
月30
日,在星期上面也是完全相同的。
原來,數字有規律性和周期性。高斯于是提出了“同余式”的理論。
當a
除以m
所得余數,和b
除以m
所得余數相同的時候,就將它寫成:a ≡ b(mod m)
。稱為整數a
,b
對模m
同余。而上面的這個算式就是同余式。在這里,mod
表示整除后取余的意思。同C
語言的%
運算符的功能是一樣的。
比如3 ≡ 1 (mod 2)
,27 ≡ 2 (mod 5)
。
同余式可以相加。
比如,當除以7
的時候,10
和17
的余數為3
,9
和16
的余數為2
:10 ≡ 17(mod 7)
,9 ≡ 16 (mod 7)
。
將10 + 9
和17 + 16
分別再除以7
,得出的余數都是3 + 2 (5)?
,也就是說:10 + 9 ≡ 17 + 16 (mod 7)
。
不光是相加,相減,或者相乘(乘方)?,同余式依然成立。
同余式和其他的等式一樣,可以進行加法、減法、乘法(乘方)的運算。
求:13的2000次方除以12
13 ≡ 1 (mod12)
,根據同余式的性質④,能夠得出:13^2000 ≡ 1^2000 ≡ 1 (mod 12)
。余數為1
。
求:斐波那契數列中是3的倍數的項
如果用通項求:
可能不夠優雅。
不妨根據這個數列的遞推方程式,求出一開始幾項的具體數字,然后將這些數字除以3
,得出余數。
我們想要找到整數除法運算當中“余數”的周期和規律。
假設:
a n + 1 = 3 p + k a_{n+1}=3p+k an+1?=3p+k
a n = 3 q + l a_{n}=3q+l an?=3q+l
k
和l
都是0
,1
,2
三個數字當中的某個整數。
an+1
除以3
的余數為k
,而k
除以3
的余數也為k
,可以得出: a n + 1 ≡ k ( m o d 3 ) a_{n+1} ≡ k (mod3) an+1?≡k(mod3)。
同樣,an
除以3
的余數為l
,而l
除以3
的余數也為l
,可以得出: a n ≡ l ( m o d 3 ) a_{n} ≡ l (mod3) an?≡l(mod3)。
根據遞推方程式: a n + 2 = a n + 1 + a n a_{n+2} = a_{n+1} + a_n an+2?=an+1?+an?
根據同余式的性質①,得出: a n + 2 ≡ a n + 1 + a n ≡ k + l ( m o d 3 ) a_{n+2} ≡ a_{n+1} + a_n ≡ k+l (mod 3) an+2?≡an+1?+an?≡k+l(mod3)。
也就是說,想要求出an+2
除以3
的余數,就必須先求出an+1
和an
除以3
的余數,然后將兩個余數相加。
通過先前的表格,我們可以看出,如果連續2
個余數和前面的某2
個余數相同的話,那么,此后的余數都按照這個形式循環下去。
比如,第9
項和第10
項的余數與第1
項和第2
項的余數相同,所以當這個數列除以3
的時候,所得出的余數的周期為8
。
一開始的8
項當中,a4
和a8
能夠被3
整除。
所以,n
的條件為,n
是4
的倍數:4,8,12,16,20,24,28,32,···
。
線性同余法獲取偽隨機數
在C
語言中,只要調用rand()
函數,就可以得到隨機數。不過,由于借助公式產生的隨機數具有一定的規律性,因此并不是真正的隨機數,通常稱為偽隨機數。
線性同余法:如果把Ri
作為當前隨機數的話,那么下一個出現的隨機數Ri + 1
就是, R i + 1 = ( a × R i + b ) m o d c R_{i+1}=(a × R_i+b) mod c Ri+1?=(a×Ri?+b)modc
對a
、b
、c
各參數設定合適的整數后,可以從該公式獲得的隨機數的范圍就是0
到c
(不包含)?。例如,把a
設定為5
,b
設定為3
,c
設定為8
,Ri
的初始值定為了1
。
這些隨機數確實很像是無規則隨機出現的數值。不過,產生8
次隨機數后,下8
次產生的隨機數就和前面的數值相同了。這種周期性是偽隨機數的特征,也是為什么不是真隨機數的原因。
srand(time(NULL));
可以提前設定Ri
、a
、b
、c
的數值。srand()
函數中的參數time(NULL)
,是用來獲取當前時間的參數。由于每次啟動程序時的當前時間都是變化的,因此Ri
、a
、b
、c
的數值也會隨之發生變化。Ri
、a
、b
、c
的數值就稱為隨機數的種子。
而重復調用rand()
函數的話,因為Ri
、a
、b
、c
的數值都有默認值,因此每次都會生成以相同方式出現的隨機數。
參考
[1] 寫給全人類的數學魔法書
[2] 程序是怎樣跑起來的