浅析Magic Number
作者: 2006年1月21日
什么是magic number?先看看wiki给的定义:
In computer programming, a magic number is a special constant used for some specific purpose. It is called magic because its value or presence is inexplicable without some additional knowledge.
基本含义就是,一个不能提供任何额外信息的数字。而我个人更倾向下面这种定义,尽管两者在语义上是极其相似的:
A number appearing in a program whose appearance tells you nothing about its intended purpose or meaning.
magic number的翻译一般是“幻数”或者“魔数”,magic是一个充满神秘色彩的单词,表达神秘,未知等复杂的寓意,而这也正是magic number在代码中的所作所为:当你看到它时,会感到“莫名其妙”。
因此,判定一个数字是否是magic number的依据,是它的出现是否能提供足够的信息让你理解其所指代的行为和场景。
看下面的代码行:
s = 10.0 * t * t / 2.0;
这里面包含了两个数字,在这种情况,这两个数字都是magic number,因为无法从这两个数字推断出任何额外的信息。
这行代码其实是表达下面的含义:
const double g = 10.0; //用10.0作为重力加速度g = 9.8的近似值。
s = g * t * t / 2.0;
代码改成这样,我们消除了一个magic number,那么另一个呢?
另一个已经不是magic number了,因为,众所周知,这行代码其实是理想自由落体掉落的距离/时间公式,公式中的 /2.0无法用更明确的单词来表达,所以,它不是magic number。
再看一个例子:
s = 3.14159 * d;
相信很多人都能猜得到,这是根据直径计算圆周长的公式,式中3.14159是圆周率PI的近似值。一般的,用一个PI或者MATH_PI来表达是更友好的形式:
s = PI * d;
但是,即使这样,也有例外的情况:在工程计算中,有时候明确规定了计算中对PI取值的精度,例如:保留小数点后两位数字(3.14)。
这时候,如果按照上面的例子,我们需要做类似这样的定义:
const double pi_with_two_decimal_digits = 3.14; //计算中使用的PI只保留两位小数。当然,或许你有更简洁的定义方式。
s = pi_with_two_decimal_digits * d;
毫无疑问这样一来代码更复杂了,可读性并不见得有所改善。因此,这时候使用3.14作为替代品,可以认为不是一个magic number。
magic number有几个特例:
一个特例是C++中,指针初始化为0值,类似这样:
int * p = 0;
0本身并不能准确表达一个“空指针”或者类似的含义(因为缺乏类型信息),但是,在借助了语法的规定和上下文场景之后,这种表达得以实现,所以0在这种场合不是magic number。
第二个是循环变量初始化为0:
for( i = 0;//....
作为已经被广泛接受的初始化方式,也没有必要写成for( i = loop_start;或者其他形式。而在STL则使用更富含义的it = container.begin()
第三个是 ~0 或者 -1
多数情况, ~0 或 -1 用来表示某类型的每个bit都是1的数字,这种表示方法一般不受类型本身长度限制(如果写成0xFFFF就只能用在short或者更短的类型)。
这时候0和 -1 也不认为是magic number。
实际编程中,0,1和-1作为非magic number出现的频率极高,而其他数字则多数是magic number,因此不少的书籍和资料都推荐0,1,-1或其中的某几个之外的其他数字都作为magic number。但是要注意这是一个建议而非原则。
magic number的界定其实是个模糊的概念,因为对于特定的数字表达,不同领域的人的认识是不同的。
例如7.91,对于多数人来说是个magic number,但是对天文/航天领域来说它就是大名鼎鼎的第一宇宙速度。在这个领域中使用这个数值一般不会带来疑问,也就不能成为magic number。
而用来表达第一宇宙速度的常数名V1,反而更容易引起误解,尤其是对其他领域的人来说。
最后,magic number是关系代码可读性/可理解的元素,与其同时存在还有magic string,magic variable等等其他充满"magic"的元素,代码中需要消除的不仅仅是magic number。
--------------------next---------------------