[英]Would These Be Considered Magic Numbers?
我刚刚完成了为编程课程编写程序,我想避免使用魔术数字,所以这是我的问题:
在下面的函数中,我的数组索引器是否会被视为幻数?
码:
string CalcGrade(int s1, int s2, int s3, double median)
{
const int SIZE = 23;
const int LETTER_GRADE_BARRIERS[SIZE] = { 400, 381, 380, 361, 360, 341, 340, 321, 320, 301, 300, 281, 280, 261, 260, 241, 240, 221, 220, 201, 200, 181, 180 };
double finalGrade;
string letterGrade;
finalGrade = s1 + s2 + s3 + median;
if (finalGrade >= LETTER_GRADE_BARRIERS[1] && finalGrade <= LETTER_GRADE_BARRIERS[0])
{
letterGrade = "A";
}
else if (finalGrade >= LETTER_GRADE_BARRIERS[3] && finalGrade <= LETTER_GRADE_BARRIERS[2])
{
letterGrade = "A-";
}
else if (finalGrade >= LETTER_GRADE_BARRIERS[5] && finalGrade <= LETTER_GRADE_BARRIERS[4])
{
letterGrade = "B+";
}
else if (finalGrade >= LETTER_GRADE_BARRIERS[7] && finalGrade <= LETTER_GRADE_BARRIERS[6])
{
letterGrade = "B";
}
else if (finalGrade >= LETTER_GRADE_BARRIERS[9] && finalGrade <= LETTER_GRADE_BARRIERS[8])
{
letterGrade = "B-";
}
else if (finalGrade >= LETTER_GRADE_BARRIERS[11] && finalGrade <= LETTER_GRADE_BARRIERS[10])
{
letterGrade = "C+";
}
else if (finalGrade >= LETTER_GRADE_BARRIERS[13] && finalGrade <= LETTER_GRADE_BARRIERS[12])
{
letterGrade = "C";
}
else if (finalGrade >= LETTER_GRADE_BARRIERS[15] && finalGrade <= LETTER_GRADE_BARRIERS[14])
{
letterGrade = "C-";
}
else if (finalGrade >= LETTER_GRADE_BARRIERS[17] && finalGrade <= LETTER_GRADE_BARRIERS[16])
{
letterGrade = "D+";
}
else if (finalGrade >= LETTER_GRADE_BARRIERS[19] && finalGrade <= LETTER_GRADE_BARRIERS[18])
{
letterGrade = "D";
}
else if (finalGrade >= LETTER_GRADE_BARRIERS[21] && finalGrade <= LETTER_GRADE_BARRIERS[20])
{
letterGrade = "D-";
}
else if (finalGrade <= LETTER_GRADE_BARRIERS[22])
{
letterGrade = "Fail";
}
return letterGrade;
}
谢谢!
是的,除了-1,0或1之外的任何数字都可能是一个神奇的数字。
除非你是一个真正的大师,否则你可能也被允许自由使用两个权力:-)
顺便说一句,你可能可以重构那些代码,使其更容易理解,例如:
string CalcGrade (int s1, int s2, int s3, double median) {
// Grade lookup arrays. If grade is >= limit[n], string is grades[n].
// Anything below D- is a fail.
static const int Limits[] = {400, 380, 360, 340,320, 300, 280,260, 240, 220,200,180 };
static const int Grades[] = {"A+","A","A-","B+","B","B-","C+","C","C-","D+","D","D-"};
double finalGrade = s1 + s2 + s3 + median;
// Check each element of the array and, if the final grade is greater
// than or equal to, return the grade string.
for (int i = 0; i < sizeof(Limits) / sizeof(*Limits); i++)
if (finalGrade >= Limits[i])
return Grades[i];
// Otherwise, failed.
return "Fail";
}
这将删除遍布代码的魔术数字到一个区域,在这个区域中,它们的工作方式很明显(假设您很好地对齐它们)。
它也与原来的解决方案中删除的问题,以什么我们与别人,达到380.5的得分做-这不是真正的公平失败:-)或者那些的BOD一个档次分配给""
对上述400(因为没有按似乎是回归"A+"
一种方式。
在你正在做事的时尚中 ,我会说它们不是神奇的数字。 你会把它们重命名为什么? 我想不出任何有用的答案( static const int One = 1;
没用。)
400, 381,
等等线路起初对我来说更加困惑。 我会在其上面加上一些类似于// GPA times 100
来澄清。
事实上,虽然你的问题(数组索引)不是太神奇,但400...
行应该用static const int A = 400; static const int AMinus = 381;
替换static const int A = 400; static const int AMinus = 381;
static const int A = 400; static const int AMinus = 381;
然后...BARRIERS[] = {A, AMinus,}
等等。 这些绝对是有意义的常数
有替代(更清洁)的方法需要数字,绝对应该变成命名常量。 (以上建议的相同)
是。 您需要重新编译才能更改数字; 这就是问题所在。
任何类似的配置都应该是可配置的,不需要重新编译。 当然,您的配置中可能仍有数字,但在您的情况下,它似乎都是配置表的合法数据。
怎么样怎么不这样做了一点幽默的?
string CalcGrade (int s1, int s2, int s3, double median) {
int grade = median + s1 + s2 + s3;
grade = (grade>400)?400:((grade<180)?179:grade);
return
"Fail\0D-\0\0\0D\0\0\0\0D+\0\0\0C-\0\0\0C\0\0\0\0"C+\0\0\0"
"B-\0\0\0B\0\0\0\0B+\0\0\0A-\0\0\0A\0\0\0\0A+"[((grade-160)/20)*5];
}
LETTER_GRADE_BARRIERS
的定义与它们实际代表的内容不LETTER_GRADE_BARRIERS
,所以是的。 如果它是一个int和char *(标记)的结构数组,那么没有。
是的,但它们使用常量正确表示,所以没有问题。
但是,我会考虑将字母等级分配给另一个数组并将它们与障碍对齐。
我肯定会使用一个循环而不是分别写出12个案例中的每一个。
它可以看起来更简单,例如使用std::lower_bound
来查找哪个括号分数和字母数组,例如letter_grade[]= { "A", ... };
将括号转换为字母等级
是的,他们绝对是神奇的数字。 你的方式也没有帮助。 所有这些数字间隔20步(每个数字之前有额外的+1缓冲区),但这在代码中并不明显。 一个更好的实现将是这样的:
string CalcGrade(int s1, int s2, int s3, double median) {
const int MAXIMUM_GRADE = 400;
const int MINIMUM_GRADE = 180;
const int GRADE_STEP = 20;
const char* GRADES[] = { "A", "A-", "B+", "B", "B-", "C+", "C", "C-", "D+", "D", "D-" };
double finalGrade = s1 + s2 + s3 + median;
if (finalGrade >= MAXIMUM_GRADE) {
return "A+";
} else if (finalGrade <= MINIMUM_GRADE) {
return "Fail";
} else {
return GRADES[(size_t)((MAXIMUM_GRADE - finalGrade) / GRADE_STEP)];
}
}
是。 数组中的索引没有任何语义含义。 这让他们变得“神奇”。
paxdiablo的反应是一种非常好的方法,尽管我很想将限制和等级名称组合成一个类/结构。
即使保持代码结构,请考虑以下两个片段:
// original
else if (finalGrade >= LETTER_GRADE_BARRIERS[13] && finalGrade <= LETTER_GRADE_BARRIERS[12])
{
letterGrade = "C";
}
// compared to
else if (finalGrade >= MIN_C_GRADE && finalGrade < MIN_C_PLUS_GRADE)
{
letterGrade = "C";
}
第二个样本为代码附加了更多的语义含义,而不是依赖于'13'和'14'代表什么。
将它们存储在一个数组中几乎没有什么收获,因为你实际上没有迭代数组。
对魔术数字的一个很好的检查是向某人描述问题的解决方案。 如果这些数字没有出现在你的口头描述中,那么它们几乎肯定是神奇的。
如果你在谈论构成LETTER_GRADE_BARRIERS
数组内容的LETTER_GRADE_BARRIERS
,我可能LETTER_GRADE_BARRIERS
这些数字视为数据 ,而不一定是值得使用唯一名称的数字。
我猜想理想情况下它们会来自数据文件而不是嵌入到程序中,但您的任务/要求可能会另有规定。
但是,用于索引数组的数字可能值得命名。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.