Takes me really a long while pondering the answer given by @dejvuth, my mathematical intuition is simply too poor :(
I put the justification below just in case anyone hits the same confusion as I did, also kindly teach if anything wrong:
Firstly note the distributive laws in modulo:
(a + b) mod n = [(a mod n) + (b mod n)] mod n
a * b mod n = [(a mod n) * (b mod n)] mod n
Now let's define a hash function below, where 'c' is the character we currently processing, q is a small prime while m is the largest prime smaller than word size:
h = 0
for c in window:
h = ( h * q + ord(c) ) % m
For simplicity and without loss of generality, let's analyze using window size of 2, note I denote ord(c1) simply as c1, etc:
h = ( ( ( 0 * q + c0 ) % m ) * q + c1 ) % m )
= ( c0 * q^1 % m + c1 * q^0 ) % m
= ( c0 * q^1 % m + c1 * q^0 % m ) % m, due to distributive law and a % b % b = a % b
= ( c0 * q^1 + c1 * q^0 ) % m, due to distributive law
Now it becomes obvious that, even though modulo is used, the series can still be written in the form of
h = ( ∑ ci * q ^ ( n - i + 1 ) ) % m, where n is the window size.
Finally, let's see what need be done when window size is exceeded and we need to get rid of the first char in the window, still we use window size of 2 to demonstrate, please pay extra attention on which part the modulo is applied so as to get the result:
h = ( h - ( c0 * q^1 ) % m ) % m
= ( ( c0 * q^1 + c1 * q^0 ) % m - ( c0 * q^1 ) % m ) % m
= ( ( c0 * q^1 + c1 * q^0 ) - ( c0 * q^1 ) ) % m
= ( c1 * q^0 ) % m
Bang, now we get what we want, the hash value is just the same as c1 being the first char in current window, simply let the rolling go on an on until we exhaust the string.