浅析Magic Number

1922阅读 0评论2008-11-19 X7rRKZQ
分类:

浅析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---------------------

上一篇:[翻译]模块化编程:一种不使用类的方法第一部分
下一篇:FILE指针传递给DLL为何无法正确操作--隐式重复定义的陷阱