繁体   English   中英

这些被认为是魔术数字吗?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM