当人们谈论在计算机编程中使用“幻数”时,它们是什么意思?
11 回答
幻数是您的代码中的任何数字,对于知识很少的人来说不是立即显而易见的。
例如,下面的一段代码:
sz = sz + 729;
里面有一个神奇的数字,最好写成:
sz = sz + CAPACITY_INCREMENT;
一些极端的观点认为,除了 -1、0 和 1 之外,您的代码中不应该有任何数字,但我更喜欢不那么教条的观点,因为我会立即识别 24、1440、86400、3.1415、2.71828 和 1.414 - 这完全取决于你的知识。
然而,即使我知道一天有 1440 分钟,我可能仍会使用MINS_PER_DAY
标识符,因为它使搜索它们变得更加容易。谁说上面提到的容量增量也不会是 1440 并且您最终更改了错误的值?对于低数字尤其如此:双重使用 37197 的机会相对较低,将 5 用于多个事物的机会相当高。
使用标识符意味着您不必遍历所有 700 个源文件并更改729
容量730
增量的时间。您可以只更改一行:
#define CAPACITY_INCREMENT 729
到:
#define CAPACITY_INCREMENT 730
并重新编译很多。
将此与魔术常量进行对比,这是天真的人们认为仅仅因为他们从代码中删除实际数字,他们就可以改变的结果:
x = x + 4;
到:
#define FOUR 4
x = x + FOUR;
这为您的代码添加了绝对零的额外信息,完全是浪费时间。
“幻数”是出现在语句中的数字,例如
if days == 365
假设你不知道一年有 365 天,你会发现这句话毫无意义。因此,最好将所有“魔术”数字(在程序中具有某种意义的数字)分配给一个常数,
DAYS_IN_A_YEAR = 365
从那时起,与之相比。它更容易阅读,如果地球被撞得不整齐,我们会获得额外的一天......你可以轻松地改变它(其他数字可能更容易改变)。
有不止一个意思。大多数答案已经给出的答案(一个任意未命名的数字)是一个非常常见的答案,我唯一要说的是有些人走到了极端的定义......
#define ZERO 0
#define ONE 1
如果你这样做,我会追捕你,毫不留情。
但是,另一种幻数用于文件格式。它只是一个通常包含在文件中的值,它有助于识别文件格式、文件格式的版本和/或特定文件的字节序。
例如,您可能有一个幻数 0x12345678。如果您看到那个幻数,那么您可以合理地猜测您看到的是正确格式的文件。另一方面,如果您看到 0x78563412,则可以合理猜测您看到的是相同文件格式的字节序交换版本。
然而,“幻数”这个词被滥用了一点,它指的是几乎任何标识文件格式的东西——包括标题中相当长的 ASCII 字符串。
维基百科是你的朋友(幻数文章)
到目前为止,大多数答案都将幻数描述为不是自我描述的常数。作为一个有点“老派”的程序员,在过去我们将幻数描述为任何被分配了影响代码行为的特殊用途的常量。例如,数字 999999 或 MAX_INT 或其他完全任意的东西。
幻数的最大问题是它们的目的很容易被遗忘,或者在另一个完全合理的上下文中使用的值。
作为一个粗略且非常人为的例子:
while (int i != 99999)
{
DoSomeCleverCalculationBasedOnTheValueOf(i);
if (escapeConditionReached)
{
i = 99999;
}
}
使用或未命名常量的事实并不是真正的问题。在我这个糟糕的例子中,值会影响行为,但是如果我们需要在循环时更改“i”的值怎么办?
显然在上面的例子中,你不需要一个幻数来退出循环。您可以用 break 语句替换它,这是幻数的真正问题,它们是一种懒惰的编码方法,并且总是可以用不太容易失败或随着时间的推移失去意义的东西来代替。
除了应用程序本身之外,任何对任何人都没有明显意义的东西。
if (foo == 3) {
// do something
} else if (foo == 4) {
// delete all users
}
幻数是某些变量的特殊值,它会导致程序以特殊方式运行。
例如,一个通信库可能需要一个 Timeout 参数,它可以定义一个幻数“-1”来表示无限超时。
术语幻数通常用于描述代码中的一些数字常量。该数字出现时没有任何进一步的描述,因此其含义是深奥的。
使用命名常量可以避免使用幻数。
在计算中使用除 0 或 1 以外的数字,这些数字不是由某个标识符或变量定义的(这不仅可以通过在一个地方更改数字来轻松地在多个地方更改数字,而且还可以让读者清楚地知道数字是什么是为了)。
简单来说,幻数是一个三位数字,其前两位数字的平方和等于第三位数字。Ex-202,如 2*2 + 0*0 = 2*2。现在,Java 中的 WAP 接受整数并打印是否是幻数。
这可能看起来有点平庸,但在每种编程语言中都至少有一个真正的幻数。
0
我认为,在几乎每个程序员的魔杖中,它是统治它们的魔杖。
FALSE 必然是 0 TRUE 不是(FALSE),但不一定是 1!可能是 -1 (0xFFFF)
NULL 不可避免地是 0(指针)并且大多数编译器都允许它,除非它们的类型检查非常狂热。
0 是数组元素的基本索引,但在那些过于陈旧以至于基本索引为“1”的语言中除外。然后可以方便地为(i = 0; i < 32; i++) 编写代码,并期望“i”将从基数 (0) 开始,然后递增到并停止在 32-1... 的第 32 个成员一个数组,或者其他什么。
0 是许多编程语言字符串的结尾。“停在这里”的价值。
0 同样内置在 X86 指令中以“有效地移动字符串”。节省许多微秒。
程序员经常使用 0 来表示例程执行中“没有出错”。它是“非异常”代码值。可以使用它来指示缺少抛出的异常。
零是程序员最常给出的答案,即完成一些完全微不足道的工作所需的工作量,例如将活动单元格的颜色更改为紫色而不是亮粉色。“零,伙计,就像零一样!”
0 是我们渴望实现的程序中的错误数。0 个未解决的异常,0 个未终止的循环,0 个无法实际采用的递归路径。0 是我们在编程劳动、女朋友(或男朋友)“问题”、糟糕的餐厅体验和汽车的一般特性方面试图达到的渐近线。
是的,0 确实是一个神奇的数字。远比任何其他价值更神奇。没什么……咳咳,接近了。
rlynch@datalyser.com