各位觀眾、各位大大們~~~~~
這個挑戰終於來到 5日目 了~~~~~
今天廢話不多說,
讓我們馬上進入正題!
(對了,先預告個,沒意外的話今天應該是數學系列的最後一篇了,
後面應該會開始進入網頁前端的複習(排版))
會挑這個題目也是因為我記得這好像是某年 C 語言的期中考題XD
介紹就有請維基大師~~~~~
https://zh.wikipedia.org/wiki/%E5%AE%8C%E5%85%A8%E6%95%B0
完全數(Perfect number),又稱完美數或完備數,是一些特殊的自然數:
它所有的真因子(即除了自身以外的因數)的和,恰好等於它本身,
完全數不可能是楔形數、平方數、佩爾數或費波那契數。
例如:第一個完全數是6,它有因數1、2、3、6,除去它本身6外,其餘3個數相加,1+2+3 = 6,恰好等於本身。
第二個完全數是28,它有因數1、2、4、7、14、28,除去它本身28外,其餘5個數相加,1+2+4+7+14 = 28,也恰好等於本身。後面的數是496、8128。
相信看完以上說明大家就知道完全數是啥咪了吧~
事不宜遲,讓我們快來動手吧:D
let basicNum = 6;
let factorSum = 0; // 因數相加結果
for ( let i=1; i<basicNum; i++ ){
if ( basicNum%i === 0 ){
factorSum += i; // 可以整除表示為因數,把因數加起來
}
}
if ( factorSum === factorSum ){
console.log(`${basicNum} 為完全數!`);
}
看起來第 1 步成功了,就可以繼續往下走了:D
(但也許有眼尖的人發現以上這段程式有很大的問題XDDDD
這邊先不破梗,就讓我繼續陳述挑戰過程吧XD)
let basicNum = 28;
let factorSum = 0; // 因數相加結果
for ( let i=1; i<basicNum; i++ ){
if ( basicNum%i === 0 ){
factorSum += i; // 可以整除表示為因數,把因數加起來
}
}
if ( factorSum === factorSum ){
console.log(`${basicNum} 為完全數!`);
}
let basicNum = 14;
let factorSum = 0; // 因數相加結果
for ( let i=1; i<basicNum; i++ ){
if ( basicNum%i === 0 ){
factorSum += i; // 可以整除表示為因數,把因數加起來
}
}
if ( factorSum === factorSum ){
console.log(`${basicNum} 為完全數!`);
} else{
console.log(`${basicNum} 不是完全數!`);
}
What?! 14 怎麼可能是完全數!!!!!
let basicNum = 14;
let factorSum = 0; // 因數相加結果
for ( let i=1; i<basicNum; i++ ){
if ( basicNum%i === 0 ){
factorSum += i; // 可以整除表示為因數,把因數加起來
}
}
if ( basicNum === factorSum ){
console.log(`${basicNum} 為完全數!`);
} else{
console.log(`${basicNum} 不是完全數!`);
}
很好,終於正常了,呼......
- 1 一定是任何數的因數,所以factorSum設為1,迴圈改由2開始計算
let basicNum = 28;
let factorSum = 1;
for ( let i=2; i<basicNum; i++ ){ // 這邊改由 2 開始
if ( basicNum%i === 0 ){
factorSum += i;
}
}
if ( basicNum === factorSum ){
console.log(`${basicNum} 為完全數!`);
} else{
console.log(`${basicNum} 不是完全數!`);
}
- 因數是成對的,當你找到 1 個,其實另外 1 個就知道了,就不用傻傻的繼續算。
這個概念就是,
要找因數每次都會從 2 開始找,
例如 28 我就會從 2,3,4..... 找到 27,
但不覺得哪裡怪怪的嗎?
28 因數有:1,2,4,7,14,28,
因數是成對的,
第 1 個被找到的因數是 2,28/2 = 14,2 跟 14 成對,
當你找到 2,表示你其實就已經找到 14 了,
直接把因數相加 2+14 並且把迴圈終點直接改成 14,
就不用傻傻算到完。
為了讓大家知道差異,
在程式我有埋一個計算次數的變數 countTimes,
就讓我們先看先前未改的時候 28 需要幾次計算吧~
[原邏輯]
[新邏輯(改成會動態修改迴圈終點)]
let basicNum = 28; // 要拿來驗證是否為完全數的數字
let factorSum = 1; // 因數相加
let countTimes = 0; // 計算次數
let endNum = basicNum;
for ( let i=2; i<endNum; i++ ){
if ( basicNum%i === 0 ){
factorSum += i; // 先加上最初找到的因數
factorSum += basicNum/i; // 再加上該因數相對的因數
endNum = basicNum/i; // 將終點動態改成該因數相對的因數
}
countTimes++;
}
if ( basicNum === factorSum ){
console.log(`${basicNum} 為完全數!`);
} else{
console.log(`${basicNum} 不是完全數!`);
}
console.log(`本次計算次數為 ${countTimes} 次`);
計算次數從 26 次降成 5 次就能算出來!!!!!
但你會說這樣有很厲害嗎?
隨著要計算的數字越大,
需要驗證的因數範圍也會隨之變大,
那個差距是很可觀的。
如果前面不先 tune,
後面你就發現即使數字沒有很大還是會操到網頁跑不出來.......
let basicNum = 496; // 要拿來驗證是否為完全數的數字
let factorSum = 1; // 因數相加
let countTimes = 0; // 計算次數
let endNum = basicNum;
for ( let i=2; i<endNum; i++ ){
if ( basicNum%i === 0 ){
factorSum += i;
factorSum += basicNum/i;
endNum = basicNum/i;
}
countTimes++;
}
if ( basicNum === factorSum ){
console.log(`${basicNum} 為完全數!`);
} else{
console.log(`${basicNum} 不是完全數!`);
}
console.log(`本次計算次數為 ${countTimes} 次`);
let perfectArray = [];
// let basicNum = 496; // 要拿來驗證是否為完全數的數字
let factorSum = 1; // 因數相加
let countTimes = 0; // 計算次數
for ( let basicNum=2; basicNum<1000; basicNum++ ){
let endNum = basicNum;
for ( let i=2; i<endNum; i++ ){
if ( basicNum%i === 0 ){
factorSum += i;
factorSum += basicNum/i;
endNum = basicNum/i;
}
countTimes++;
}
if ( basicNum === factorSum ){
console.log(`${basicNum} 為完全數!`);
perfectArray.push(basicNum);
}
factorSum = 1; // 一次計算完就要將因數相加設成初始值 1
}
console.log(`本次計算次數為 ${countTimes} 次`);
let perfectArray = [];
// let basicNum = 496; // 要拿來驗證是否為完全數的數字
let factorSum = 1; // 因數相加
let countTimes = 0; // 計算次數
// 直到找到 4 個完全數才停止迴圈計算
for ( let basicNum=2; perfectArray.length<4 ; basicNum++ ){
let endNum = basicNum;
for ( let i=2; i<endNum; i++ ){
if ( basicNum%i === 0 ){
factorSum += i;
factorSum += basicNum/i;
endNum = basicNum/i;
}
countTimes++;
}
if ( basicNum === factorSum ){
console.log(`${basicNum} 為完全數!`);
perfectArray.push(basicNum);
}
if ( perfectArray.length == 4 ){
break; // 當已經找到第 4 個完全數,任務也完成了,就跳出迴圈不要再計算了
}
factorSum = 1;
}
本日任務打完收工~~~~~~
之所以為什麼是找出 4 個不是 5 個呢?
因為~~~ 跑到第 5 個網頁就轉圈圈了orz
可以看到跑到第 4 個,計算次數就來到 10246704 次了orz
所以我想這個程式還有很大空間可以 tune,
有機會想要再 tune tune 看!
(但我不想用維基說的數學家已知規律去找,因為我想以未知情況去探索的邏輯來寫,
直接套已知規律就失去程式練功的意義了)
也許有路過的大大們可以給小的建議,
也很歡迎跟小的講,也許就可以變成隔天文章了呢~
好的,今日節目到這告一段落,
讓我們明天再見吧~~~~~~:D