这篇文章是关于数学中一个常见的概念——余数。
提起余数,想必大家都不陌生,我们生活中就有许多关于余数的例子。
比如,今天是星期二,你想知道30天之后是星期几,就可以用 30 除以 7(一周七天),余 2,最后在今天的基础上加上两天,这样你就知道了,30天后是周四。
再比如,我们做 Web 编程时,经常要用到分页的概念。如果你要展示 1123 条数据,每页 10 条,那么该怎么计算总共的页数呢?大部分人可能都会想到,用 1123 除以 10,得到商是 112,余数是 3,所以你的页数就是 112 + 1 = 113,而最后的余数就是多出来,凑不够一页的数据。
再有就是我之前在讲结构体的内存对齐模式时说的页式管理,也是用到了余数。
据此我们可以发现余数的一个重要特点,余数总是在一个固定的范围内。
比如你拿任何一个整数除以 7,得到的余数肯定是在 0~6 之间的某一个数。所以当我们知道1900年的1月1日是星期一,那么便可以知道这一天之后的第一万甚至十万天是星期几。
我们都知道,整数是没有边界的,它可能是正无穷,也有可能是负无穷。但是余数却可以通过某一种关系,让整数处于一个可以确定的边界内。就像人类发名的星期或者礼拜,七天一个轮回,周而复始地过完一生。不管你身处哪个时刻,都身处周期内。
再看之前的例子,假如今天是周一,从今天开始的 100 天里,都有多少个星期呢?用 100 除以 7,得到商 14 余 2,也就是说这 100 天里有 14 周多 2 天。换个角度看,这 100 天里,第 1 天,第 8 天,第 15 天等等,在余数的世界里都被认为是同一天,因为它们的余数都是 1,都是星期一。
这些数的余数都是一样的,所以被归类到了一起。我们的前人早已注意到了这一规律或者特点,所以他们把这一结论称为同余定理。简单来说,就是两个整数 a 和 b,如果它们除以正整数 m 得到的余数相等,我们就可以说 a 和 b 对于模 m 同余。
也就是说,上面我们说的 100 天里,所有星期一的这些天就是同余的,同理,星期二、星期三等等这些天也是同余的。
还有我们经常提到的奇数和偶数,其实也是同余定理的一个应用。当然,这个应用里,它的模就是 2。2 除以 2 余 0,所以它是偶数;3 除以 2 余 1,所以它是奇数。2 和 4 除以 2 都余 0,所以它们是一类的,都是偶数;3 和 5 除以 2 都余 1,所以它们都是一类,都是奇数。
那么,同余定理到底是做什么的呢?从前面的例子中我们已经可以得出结论了。
同余定理实际上就是用来分类的。
我们有无穷多个整数,怎么能够全面、多维度地管理这些整数?同余定理就提供了一个思路。
不管你的模是几,最终得到的余数肯定都在一个范围内。比如上面我们除以 7,就得到了星期几;除以 2,就得到了奇偶数。所以按照这个方式,我们就可以把无穷多个整数分成有限多个类。这一点在我们的计算机中,就可以起到很大的作用。
哈希(Hash)你可能听过,在每个编程语言中,都会有对应的哈希函数。哈希有时候也会被翻译成散列,简单来说,它就是将任意长度的输入,通过哈希算法,压缩为某一固定长度的输出。
这不就是取余嘛!
举个例子,假如你想要快速读写 100 万条数据记录,要达到高速地存取,最理想的情况当然是开辟一个连续的空间存放这些数据,这样就可以减少寻址的时间。但是由于条件的限制,我们并没有能够容纳 100 万条记录的连续地址空间,那应该怎么办呢?
我们可以考察一下,看看系统是否可以提供若干个较小的连续空间,而每个空间又能存放一定数量的记录。比如我们找到了 100 个较小的连续空间,也就是说,这些空间彼此之间是被分隔开来的,但是内部是连续的,并足以容纳 1 万条记录连续存放,那么我们就可以使用余数和同余定理来设计一个散列函数,并实现哈希表的结构。
在这个公式中,x 表示等待被转换的数值,而 size 表示有限存储空间的大小, mod 表示取余操作。通过余数,你就可以将任何数值,转换为有限范围内的一个数值,然后根据这个新的数值,来确定将数据存放在何处。
具体来说,我们可以通过记录标号模 100 的余数,指定某条记录存放在哪个空间。这个时候公式就变成了????
f(x) = x mod 100
假设有两条记录,它们的记录标号分别是 1 和 101。我们把这些模 100 之后余数都是 1 的,存放到第 1 个可用空间里,以此类推。
这样我们就可以根据求余的快速数字变化,对数据进行分组,并把它们存放到不同的地址空间里。而求余操作本身很简单,所以不会增加寻址时间。
除此之外,为了增加数据散列的随机程度,我们还可以在公式中加入一个较大的随机数 MAX,于是,上面的公式就可以写成下面这样????
我们假设随机数 MAX 是 18322 ,那么我们针对标号为 1 的记录进行重新计算,最后结果就是 23,针对标号 101 的记录,如果随机数 MAX 取 627901,对应的结果应该是 2。这样先前被分配到空间 1 的两条记录,在新的计算公式作用下,就会被分配到不同的可用空间中。
这样,使用了 MAX 这个随机数之后,被分配到同一空间中的记录就更加“随机”,更适合需要将数据重新洗牌的应用场景,比如加密算法,MapReduce中的数据分发,记录的高速查询和定位等等。
至此,余数的内容就说完了,数学思想在计算机中的重要性和普遍性可见一斑。
另,这篇文章的知识点来源于极客时间黄申的《程序员的数学基础课》。