取模速度優化

2021-06-14 17:16:47 字數 1505 閱讀 1348

做acm題時,經常遇到取模操作,而取模操作是算術操作中最慢的(在當前的計算機硬體中基本都是這樣)。

1 對2的冪取模(2^k),實際等同於和(2^k - 1)進行「位與」操作

例如對8取模,因為計算機內部是二進位制表示,所以可以對二進位制位進行位與操作。

n % 8 == ( n & 7 )  // 因為c語言取模操作會返回負數,所以當n是負數時,它們是同模關係。

2 經常有一些遞推式,是加和後求模關係,這時可以利用有限範圍的特性,將求模轉換為加減法

// 例如dp[0] = dp[1] = 1

dp[i] = ( dp[i-1] + dp[i-2] ) % mod;

// 注意dp陣列都是正數,並且兩個元素加和在[0,2*mod) 範圍。

// 公式可以改寫為

int madd[2] = , r;

r = dp[i-1] + dp[i-2] - mod;

dp[i] = r + madd[((unsigned)(r))>>31];

3 有些題目結果是高精度(即用語言提供的型別已經無法表示,必須用陣列模擬),通常的做法是用乙個32bit的int表示10^9進製的數。

這樣做確實很直觀,也符合我們十進位制的直覺,但是每次進製都不可避免要進行取模和除法操作,非常慢。

可以考慮用2^30進製,這樣進製時用的就是「移位」和「位與」運算,可以很大提高執行速度。

當然最後也會產生乙個問題,就是2^30進製表示法無法直接列印,這時還需要將2^30進製轉換為10^9進製再輸出。由於往往只列印一次,所以基本不費什麼時間。

// 例如2^30加法

#define len 5 // 每個高精度用幾個int

#define p2 30 // 2^p2 進製

#define m2 ( (1<> p2 );

c[i-1] &= m2;

}}

下面是2^30轉換為10^9進製並列印的**:

#define  m10  1000000000

void convert_print( int* d2 ) ;

int i = len - 1, j, k = 0;

ll r;

while( i >= 0 )

d10[k++] = r;

}char buf[len*9+1];

int pos = 0;

for( i = len - 1; i > 0; --i ) if( d10[i] ) break;

pos += sprintf( buf + pos, "%d", d10[i] );

for( --i; i >= 0; --i ) pos += sprintf( buf + pos, "%09d", d10[i] );

buf[pos] = 0;

puts( buf );

}

取模運算相關的常數優化

首先,若模數 p 2 2 直接利用unsigned unsigned long long自然溢位即可,方便而且快。若 p 是其它 2 的整數次冪,可以通過位運算優化取模 用x p 1 代替x p。這種情況好像基本沒見過 若 p 很小,例如 p 2022 那麼可以放心地用int,少量取模保證不溢位即可...

HashMap 優化 使用 運算 來實現取模

1.前提條件 值必須是2的冪次方,看j a1.8 hashmap原始碼 2.找到 if p tab i n 1 hash null n必須是2的倍數 首先是hash這個值,轉成二進位制,就是0和1,我們先用個例子來說明下,n 4,hash 13 13的二進位制是1101 4的二進位制是 0100 高...

取模與取餘

通常情況下取模運算 mod 和求餘 rem 運算被混為一談,因為在大多數的程式語言裡,都用 符號表示取模或者求餘運算。在這裡要提醒大家要十分注意當前環境下 運算子的具體意義,因為在有負數存在的情況下,兩者的結果是不一樣的。對於整型數a,b來說,取模運算或者求餘運算的方法都是 1.求 整數商 c a ...