Magic Number 0x3f3f3f3f
在做算法题时,我们常常需要用到一个能够表示“无穷大”的值INF
,最容易想到的,我们可以把INF
设为0x7fffffff
,因为这是32位int
的最大值。如果这个无穷大只用于一般的比较(比如求最小值时min
变量的初值),那么0x7fffffff
确实是一个完美的选择。但是更多情况下,0x7fffffff
并不是一个最好的选择,比如在Dijkstra算法中,我们使用松弛操作:
if (dist[u] + weight[u][v] < dist[v]) |
如果u
和v
之间没有边,那么weight[u]=INF
,如果此时将INF
取作0x7fffffff
,那么dist[u] + weight[u][v]
就会向上溢出而变成负数,我们的松弛操作便出错了!
准确来说,0x7fffffff
在作为32位整数的情况下不能满足无穷大加无穷大依然是无穷大这个条件,一旦溢出就变成了一个很小的负数。
可以考虑这样一个取值INF=0x3f3f3f3f
,0x3f3f3f3f
的十进制是1061109567
,是109级别的(和0x7fffffff
一个数量级),而一般场合下的数据都是小于109的,所以它可以作为无穷大使用而不致出现数据大于无穷大的情形。
另一方面,由于一般的数据都不会大于109,所以当我们把无穷大加上一个数据时,它并不会溢出。事实上0x3f3f3f3f + 0x3f3f3f3f = 0x7E7E7E7E
,非常大但却没有超过32位int
的表示范围,所以满足了我们“无穷大加无穷大依然是无穷大”的需求。
最后,之所以选择0x3f3f3f3f
而不是0x3f000000
,是因为如果我们想要将某个数组快速初始化为某个值,通常会使用cstring头文件中的函数memset(a, 0, sizeof(a))
,方便又高效。因为memset
是按字节操作的(所以通常只能用来初始化数组为全0
或全-1
),所以我们只需要memset(a, 0x3f, sizeof(a))
,就可以把数组全部初始化为0x3f3f3f3f
。