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