简体   繁体   English

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

[英]Would These Be Considered Magic Numbers?

I've just completed writing a program for a programming class, and I want to avoid use of magic numbers, so here's my question: 我刚刚完成了为编程课程编写程序,我想避免使用魔术数字,所以这是我的问题:

In the function below, would my array indexers be considered magic numbers? 在下面的函数中,我的数组索引器是否会被视为幻数?

Code: 码:

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;
}

Thanks! 谢谢!

Yes, any number other than -1,0 or 1 is probably a magic number. 是的,除了-1,0或1之外的任何数字都可能是一个神奇的数字。

Unless you're a real guru, then you're probably allowed to use powers of two freely as well :-) 除非你是一个真正的大师,否则你可能也被允许自由使用两个权力:-)

As an aside, you could probably refactor that code to be a little more understandable, something like: 顺便说一句,你可能可以重构那些代码,使其更容易理解,例如:

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";
}

This removes the magic numbers spread all over the code to an area where it's immediately obvious how they work (assuming you align them nicely). 这将删除遍布代码的魔术数字到一个区域,在这个区域中,它们的工作方式很明显(假设您很好地对齐它们)。

It also removes a problem with your original solution as to what we do with someone that achieved a score of 380.5 - it's not really fair to fail those bods :-) Or to assign a grade to "" to those above 400 (since there doesn't appear to be a way to return "A+" ). 它也与原来的解决方案中删除的问题,以什么我们与别人,达到380.5的得分做-这不是真正的公平失败:-)或者那些的BOD一个档次分配给""对上述400(因为没有按似乎是回归"A+"一种方式。

In the fashion you are doing things , I would say they are not magic numbers. 在你正在做事的时尚中 ,我会说它们不是神奇的数字。 What would you rename them? 你会把它们重命名为什么? I can't think of any useful answer ( static const int One = 1; is useless.) 我想不出任何有用的答案( static const int One = 1;没用。)

The 400, 381, etc. line is more confusing to me at first. 400, 381,等等线路起初对我来说更加困惑。 I would put something like // GPA times 100 above it to clarify. 我会在其上面加上一些类似于// GPA times 100来澄清。

In fact, while your question (array indexes) isn't too magical, the 400... line should probably be replaced with static const int A = 400; static const int AMinus = 381; 事实上,虽然你的问题(数组索引)不是太神奇,但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; then ...BARRIERS[] = {A, AMinus,} and so on. 然后...BARRIERS[] = {A, AMinus,}等等。 Those are definitely meaningful constants 这些绝对是有意义的常数

There are alternate (cleaner) methods that would need numbers that should definitely be turned into named constants. 有替代(更清洁)的方法需要数字,绝对应该变成命名常量。 (The same ones suggested above) (以上建议的相同)

Yes. 是。 You need to recompile to change the numbers; 您需要重新编译才能更改数字; that's where the problem lies. 这就是问题所在。

Any configuration things like that should be, well, configurable, and not require a recompliation. 任何类似的配置都应该是可配置的,不需要重新编译。 Of course, you may still have numbers in your config, but in your case, it all seems like legitimate data for a configuration table. 当然,您的配置中可能仍有数字,但在您的情况下,它似乎都是配置表的合法数据。

How about how not to do it for a bit of humour? 怎么样怎么这样做了一点幽默的?

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];
}

The definition of LETTER_GRADE_BARRIERS is disjoint from what they actually represent, so yes. LETTER_GRADE_BARRIERS的定义与它们实际代表的内容不LETTER_GRADE_BARRIERS ,所以是的。 If it was an array of structs of an int and a char* (the mark) then no. 如果它是一个int和char *(标记)的结构数组,那么没有。

Yes, but they are properly represented using constants, so no problems there. 是的,但它们使用常量正确表示,所以没有问题。

I would, however, consider assigning the letter grades to another array and aligning them with the barriers. 但是,我会考虑将字母等级分配给另一个数组并将它们与障碍对齐。

And I would definitely use a loop and not write out each of the 12 cases seperately. 我肯定会使用一个循环而不是分别写出12个案例中的每一个。

it can look a lot simpler, for example using std::lower_bound to find which bracket score belongs to and array of letters , eg letter_grade[]= { "A", ... }; 它可以看起来更简单,例如使用std::lower_bound来查找哪个括号分数和字母数组,例如letter_grade[]= { "A", ... }; to convert bracket to a letter grade 将括号转换为字母等级

Yes, they are most definitely magic numbers. 是的,他们绝对是神奇的数字。 The way you are going about it doesn't help either. 你的方式也没有帮助。 All these numbers are spaced 20 steps apart (with an extra +1 buffer before each) but that is not apparent from the code. 所有这些数字间隔20步(每个数字之前有额外的+1缓冲区),但这在代码中并不明显。 A much better implementation would be something like this: 一个更好的实现将是这样的:

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)];
  }
}

Yes. 是。 The indices into the array have no semantic meaning whatsoever. 数组中的索引没有任何语义含义。 This makes them 'magic.' 这让他们变得“神奇”。

paxdiablo's response is a pretty good way of doing it, though I'd be tempted to combine the limit and grade name into a single class/struct. paxdiablo的反应是一种非常好的方法,尽管我很想将限制和等级名称组合成一个类/结构。

Even keeping the code structure, consider these two fragments: 即使保持代码结构,请考虑以下两个片段:

// 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";
}

The second sample attaches more semantic meaning to the code, rather than relying upon what '13' and '14' represent. 第二个样本为代码附加了更多的语义含义,而不是依赖于'13'和'14'代表什么。

Storing them in an array buys you little, as you're not actually iterating over the array. 将它们存储在一个数组中几乎没有什么收获,因为你实际上没有迭代数组。

A good check for magic numbers is to describe the solution to the problem to someone. 对魔术数字的一个很好的检查是向某人描述问题的解决方案。 If the numbers don't show up in your verbal description, they're almost certainly magic. 如果这些数字没有出现在你的口头描述中,那么它们几乎肯定是神奇的。

If you're talking about the numbers that make up the contents of the LETTER_GRADE_BARRIERS array, I'd probably consider those numbers as data , not necessarily numbers that deserve unique names. 如果你在谈论构成LETTER_GRADE_BARRIERS数组内容的LETTER_GRADE_BARRIERS ,我可能LETTER_GRADE_BARRIERS这些数字视为数据 ,而不一定是值得使用唯一名称的数字。

I'd guess that ideally they would come from a data file rather than embedded in the program, but your assignment/requirements might dictate otherwise. 我猜想理想情况下它们会来自数据文件而不是嵌入到程序中,但您的任务/要求可能会另有规定。

However, the numbers that are used to index the array might well deserve names. 但是,用于索引数组的数字可能值得命名。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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