# 2020q3 Homework5 (quiz5) contributed by < `jeremy3951` > ###### tags: `(2020q3)進階電腦系統理論與實作` ## 題目2. 牛頓逼進法 qq1 : 把數值放到對的地方 ## 題目3. ### 解題思路 : 觀察 for 迴圈的中止條件 : `i >= x` 再觀察 `x+= ZZZ` 這行 , 可得知 ZZZ 一定 <0 (不然迴圈不會停止) 選項中只有 (d) 選項 < 0 , 所以答案為 (d) ### 運作原理 : 擷取自[文章](https://blog.csdn.net/zhangpeterx/article/details/100735382)中 思路是: let N = k + (k+1) + (k+2) + (k+3) + … + (k+i-1) = ik + (1+2+3+… + i-1) let sum(i) = (1+2+3+…+i-1), then we have N = sum(i) + ik ==>i*k = N - sum(i) Which means: for each i, we can calculate N-sum(i). If N-sum(i) can be divided by i, there is an answer with length i. **要把 i 看成等差數列的長度 !!** 文章中的解法如下 : ```cpp int consecutiveNumbersSum(int N) { int sum = 0, ans = 0; for(int i = 1; sum < N; i++) { sum += i; if (((N-sum) % i) == 0) ans++; } return ans; } ``` 再看回原本的題目 : ( 擷取部分而已 ) ```cpp int ret = 1; int x = N; for (int i = 2; i < x; i++) { x += 1 - i; if (x % i == 0) ret++; } ``` 起初我以為 ret 的初始值為 1 和 i 從 2 開始都是因為 : `(x % 1)==0` 一定會成立 , 所以省掉這步直接從 i=2 開始執行 第一步如下 : ( 我當時以為的 ) 根據前面參考的程式碼 `if((N-sum)%i==0)` 第一步為 `N -( 1+2)` , 然後再看 N % 2 是否等於 0 以 N=9 為例子 , 9-(1+2)=6 , 再看 6 % 2 是否等於 0 可是 , 此時看回原本的題目 : `x += 1 - i;` 9 + 1 - 2 = **8!!** 跟原本的數字不一樣了 ! 再繼續往下 trace : `(x % i == 0) ?` 8 % 2 = 0 ( 還真的等於 0 ) ~~會是巧合嗎 ?~~ 於是我就繼續往下 trace : 網路上參考的程式碼 : ( ret = 0 ) 9 - 1 = 8 ----------> 8 % 1 =0 ,ret++ 9 - 1 - 2 = 6 ------> 6 % 2 =0 , ret++ 9 - 1 - 2 - 3 = 3 --> 3 % 3 = 0 , ret++ 老師出的題目 : ( ret = 1 ) 9 + 1 - 2 = 8 --> 8 % 2 = 0 , ret++ 8 + 1 - 3 = 6 --> 6 % 3 = 0 , ret++ 6 + 1 - 4 = 3 --> 3 % 4 = 3 , ret 不變 雖然看起來不一樣 , 但是經過整理一下 : 老師出的題目 : ( ret = 1 ) 9 + 1 - 2 = 8 ------------------> 8 % 2 = 0 , ret++ 9 + 1 - 2 + 1 - 3 = 6 ----------> 6 % 3 = 0 , ret++ 9 + 1 - 2 + 1 - 3 + 1 - 4 = 3 --> 3 % 4 = 3 , ret 不變 再把左式同時 +1 -1 : 老師出的題目 : ( ret = 1 ) 9 + 1 - 1 + 1 - 2 = 8 ------------------> 8 % 2 = 0 , ret++ 9 + 1 - 1 + 1 - 2 + 1 - 3 = 6 ----------> 6 % 3 = 0 , ret++ 9 + 1 - 1 + 1 - 2 + 1 - 3 + 1 - 4 = 3 --> 3 % 4 = 3 , ret 不變 整理一下 : 9 - 1 - 2 + 2 = 8 ----------> 8 % 2 = 0 , ret++ 9 - 1 - 2 - 3 + 3 = 6 ------> 6 % 3 = 0 , ret++ 9 - 1 - 2 - 3 - 4 + 4 = 3 --> 3 % 4 = 3 , ret 不變 +2 +3 +4 不會影響到後面的 %2 %3 %4 的結果可以拿掉 , 拿掉後 : 9 - 1 - 2 ~~+ 2~~ = 8 - 2 ----------> (8 - 2) % 2 = 0 , ret++ 9 - 1 - 2 - 3 ~~+ 3~~ = 6 - 3 ------> (6 - 3) % 3 = 0 , ret++ 9 - 1 - 2 - 3 - 4 ~~+ 4~~ = 3 - 4 --> (3 - 4) % 4 = 3 , ret 不變 得知 ```cpp for (int i = 2; i < x; i++) { x += 1 - i; if (x % i == 0) ret++; } ``` 等價於 ```cpp for(int i = 1; sum < N; i++) { sum += i; if (((N-sum) % i) == 0) ans++; } ``` ### 推導更正 : 根據題目中的片段 : $N-\dfrac{(k-1)k}{2}\ > 0$ 從而推得近似解 : $k< \sqrt{2N}$ 我的推導 : $N-\dfrac{(k-1)k}{2}\ > 0$ $N> \dfrac{(k-1)k}{2}> \dfrac{(k-1)(k-1)}{2}> \dfrac{(k-1)^2}{2}$ $2N > (k-1)^2$ $\sqrt{2N} > (k-1)$ $\sqrt{2N} >= k$ k 應改為 **小於等於** $\sqrt{2N}$ 才對 ### 改寫分析 : 照著老師給的公式 : $kx=N- \dfrac{(k-1)k}{2}$ 自己針對迴圈內部改寫了程式碼如下 : ```cpp for (int i = 1; i < x; i++) { x=N; x -= ((i-1)*i)/2; if ((x%i==0)) ret++; } ``` 結果跟老師原本的程式碼跑出一樣的結果 ![](https://i.imgur.com/zIcMIbt.png) 我又提交了另一個版本 : (把迴圈內的 % 運算換掉) ```cpp bool divisible(uint32_t n ,int D) { uint64_t M = (UINT64_C(0xFFFFFFFFFFFFFFFF) / (D) + 1); return n * M <= M-1; } int consecutiveNumbersSum(int N) { if (N < 1) return 0; int ret = 1; int x = N; for (int i = 2; i < x; i++) { x += 1-i; if (divisible(x,i)) ret++; } return ret; } ``` 結果就妙了... ![](https://i.imgur.com/dkTfe9r.png) 這四次都是一樣的程式碼 , 但跑出來的時間卻有點不同 於是我就想測試我第一個版本的程式碼 .... ![](https://i.imgur.com/8jjwRw4.png) 果然也是這樣 !! 這我就不懂了...