CHZhan
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # 2020q3 Homework5 (quiz5) contributed by < `RainbowEye0486` > ## 測驗一 ```cpp= #include <stdio.h> #include <stdlib.h> double divop(double orig, int slots) { if (slots == 1 || orig == 0) return orig; int od = slots & 1; double result = divop(orig / 2, od ? (slots + 1) >> 1 : slots >> 1); if (od) result += divop(result, slots); return result; } ``` ### 程式碼討論 假設舉例 $orig=2.4$ 、 $slots=3$ 我們預期得到的結果會是 0.8 。 根據遞迴的方式,我們發現浮點數 2.4 除 3 之後的結果會是 `divop(2.4, 3)` + `divop(0.6, 3)` +`divop(0.3, 3)` +...=0.8 >我們發現第二項的參數傳入其實是由第一項計算出來的答案繼續往下遞迴的,事實上,如果 $slots$ 中有除了2的冪次以外的因數,其除法就不能直接以二進制表示,需要遞迴運算直到 `result` 的 `fraction` 紀錄不下為止。如果以 $2.4/3$ 為例,就運算了 **1067** 次之多。 分析程式碼的部份: 先看當 $slots$ 是偶數的情形 $divop(orig/2, slots>>1) = \frac{\frac{orig}{2}}{\frac{slots}{2}}$ 我們可以把它理解為被除數和除數先提出一個 2 的公因式再繼續下去運算,代表的值沒有改變,接下來看奇數的情形: $divop(orig/2, slots+1>>1)$ $= \frac{\frac{orig}{2}}{\frac{slots+1}{2}}$ $= \frac{(orig)slots}{(slots+1)slots}$ $= \frac{orig(slots+1)}{(slots+1)slots}-\frac{orig}{(slots+1)slots}$ $= \frac{\frac{orig}{2}}{\frac{slots}{2}}-\frac{orig}{(slots+1)slots}$ $= result$ 需要加上 $\frac{orig}{(slots+1)slots}$ 得到的才會是我們真正想要的解 $\frac{\frac{orig}{2}}{\frac{slots}{2}}$ $\frac{orig}{(slots+1)slots}$ 可以再表示成 $\frac{\frac{orig}{2}}{(slots+1)\frac{slots}{2}}=\frac{\frac{orig}{2}}{\frac{slots+1}{2}}/slots$ ,也就是 $\frac{result}{slots}$ ,因此改寫成 $divop(result, slots)$ Ans: **D1 = 2 D2 = 1** :::info :bulb:當除數過大或是一連串奇數相乘,遞迴呼叫過多次效率反而比直接使用除法(/)降低許多,探究其原因是因為多層遞迴呼叫的關係,不曉得使用時機是什麼時候?或許是當除數比較小的時候所實現的快速浮點數除法? ::: --- ### 比照浮點數運算和定點數操作,改寫上述程式碼,提出效率更高的實作,並與使用到 FPU 的實作進行效能比較 參照 IEEE754 對於 `double` 的規範,實做較為迅速的 `div2` : ```cpp double div2(double dou) { u_int64_t ud = *(u_int64_t *)&dou; // assert(sizeof(u_int64_t), sizeof(long long int)); printf("uint64 %llu\n", (long long int)ud); u_int64_t ud_sgn = (ud >> 63) & 0x01; //extract sign bit u_int64_t ud_exp = (ud >> 52) & 0x7ff;//extract exponent if (ud_exp == 0) {//denormalized ud = ud >> 1; ud &= 0x7fffffffffffffff; ud += (ud_sgn <<63); } else if (ud_exp != 0x7ff) {//+Inf or NaN ud_exp -=1; ud &= 0x800fffffffffffff; ud = ud + (ud_exp << 52); printf("uint64 %d\n", ud); } return *(double*)&ud; } ``` 這邊直接使用了 double 的 biteise 運算實做除法,按照以下步驟完成: 1. 浮點數轉型成 `uint64` 的方式儲存,方便我們直接對位元操作 2. 用 `bit mask` 分別抓出 `sign bit` 和 `exponent` 項 3. 如果 `exponent` 項全為零,代表 denormalized ,直接把 `fraction` **右移**處理然後把 `sign bit` 放回 4. 如果 `exponent` 項不全為1,代表為 normalized number ,**`exponent` -1** 後將 `sign bit` 和 `exponent` 項放回 5. 其他種情形(Inf、NaN)直接回傳 #### 效能檢測 --- ## 測驗二 ![](https://i.imgur.com/w23kYSj.png) - 表一:IEEE754浮點數規範 ```cpp /* Set a float from a 32 bit int. */ #define INSERT_WORDS(d, ix0) \ do { \ ieee_float_shape_type iw_u; \ iw_u.v_int = (ix0); \ (d) = iw_u.value; \ } while (0) /* Get a 32 bit int from a float. */ #define EXTRACT_WORDS(ix0, d) \ do { \ ieee_float_shape_type ew_u; \ ew_u.value = (d); \ (ix0) = ew_u.v_int; \ } while (0) ``` 這邊的兩個巨集分別是 1. 將32 bit int 的 `ix0` 轉成 float 的 `d` 2. 將float 的 `d` 轉成 32 bit int 的 `ix0` ```cpp float z; int32_t sign = 0x80000000; uint32_t r; int32_t ix0, s0, q, m, t, i; ``` 接著是變數的宣告,並且我們注意到 `sign` 代表的意思是 32 bit int 的第一個 `sign bit` 的 mask ,而 `ix0` 代表的是我們要把浮點數轉成整數型態儲存 ```cpp /* take care of zero */ if (ix0 <= 0) { if ((ix0 & (~sign)) == 0) return x; /* sqrt(+-0) = +-0 */ if (ix0 < 0) return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ } ``` 處理傳入浮點數是正負零或是負數的情況。如果是正負零,我們用 `(~sign)` 判斷除了 `sign bit` 以外的其他位元是不是都為零。如果全為零,則直接回傳0。 如果是負數,回傳 0/0 ,也就是 `NaN`。 ```cpp /* take care of +INF and NaN */ if ((ix0 & 0x7f800000) == 0x7f800000) { /* sqrt(NaN) = NaN, sqrt(+INF) = +INF,*/ return x; } ``` 現在的 `ix0` 已經是一個正數,但是我們還需要處理原本的浮點數如果是(正)無限大或是 `NaN` 的情況,根據表一,擔這兩種狀況發生的時候,中間的 Exponent 項會全部都是 1,所以我們需要用一個 mask `0x7f800000` 去判斷 `ix0` 指數項以排除(正)無限大或是 `NaN` 的情況。 ```cpp /* normalize x */ m = (ix0 >> 23); if (m == 0) { /* subnormal x */ for (i = 0; (ix0 & 0x00800000) == 0; i++) ix0 <<= 1; m -= i - 1; } ``` 右移了 23 個位元後得到 `m` 是浮點數的指數項( exponent ),如果全部為零,排除掉0的可能性只可能會是 `denormalized` 浮點數,將其正規化,方式是將 `fraction` 的部份右移直到他的第一個位元是 1 ,而這時候我們的 `m` 也會相對應的變小。 ```cpp m -= 127; /* unbias exponent */ ix0 = (ix0 & 0x007fffff) | 0x00800000; if (m & 1) { /* odd m, double x to make it even */ ix0 += ix0; } m >>= 1; /* m = [m/2] */ ``` 減掉了 bias 的 127 之後才是真正的指數次方。 透過`ix0 = (ix0 & 0x007fffff) | 0x00800000` 擷取 `fraction` 的部份,並且設定第 24 bit 為 1 ,得到 $1.fraction$ 根據[以牛頓法求整數開二次方根的近似值](http://science.hsjh.chc.edu.tw/upload_works/106/44f6ce7960aee6ef868ae3896ced46eb.pdf)中得到 $\sqrt{N}$ 在 x 軸的第一個近似值為: $\sqrt{N}$ $=\frac{a(n-1)+\frac{N}{a^{n-1}}}{n}$ $=\frac{a+\frac{N}{a}}{2}$ ```cpp /* generate sqrt(x) bit by bit */ ix0 += ix0; q = s0 = 0; /* [q] = sqrt(x) */ r = QQ0; /* r = moving bit from right to left */ while (r != 0) { t = s0 + r; if (t <= ix0) { s0 = t + r; ix0 -= t; q += r; } ix0 += ix0; r >>= 1; } ``` ```cpp /* use floating add to find out rounding direction */ if (ix0 != 0) { z = one - tiny; /* trigger inexact flag */ if (z >= one) { z = one + tiny; if (z > one) q += 2; else q += (q & 1); } } ix0 = (q >> 1) + QQ1; ix0 += (m << QQ2); ``` ## 測驗三 ```cpp= int consecutiveNumbersSum(int N) { if (N < 1) return 0; int ret = 1; int x = N; for (int i = 2; i < x; i++) { x += ZZZ; if (x % i == 0) ret++; } return ret; } ``` --- ### 程式碼解析 從原方程式的 $kx=N-\frac{(k-1)k}{2}$ 我們將它理解為 $kx=N-\{1+2+...+(k-1)\}$ 也就是 $N$ 減掉從 1 到 k-1 之間連續正整數的和,假如我們能夠找到 $k=i$ ,且 $k$ 為正整數,使得等號成立,那必定存在一組連續正整數的和等於 $N$ ,也就是說, $N-\{1+2+...+(k-1)\}$ 能夠被 $x$ 整除,這個狀況下的 $k$ 便是一個可行解。 回到題目本身 **第3行:** 當 $N<1$ 的情況無法形成任何連續正整數的和,因此直接回傳0。 **第5行:** 對於任何大於 1 的正整數來說,至少都能夠表示成只有自己的連續正整數和,因此起始值為一,這邊其實有另一個意思,也就是說當 $k=1$ 時,$x=N-\{(1-1)\}$ 的時候,只要令 $x=N$ ,則頂事必定會成立。 我們用 9 當作例子: |iteration| x | i | ret | | --- | --- | --- | --- | |1|9|2|1| |2|8|3|2| |3|6|4|3| 最後回傳的答案是 3,為什麼呢?我們令 $N=9$ 以及 $k=2$ (這邊的 $k$ 和 $i$ 是相同意思,因為 $k=1$ 我們已經討論過必定成立,所以程式碼從 $k=2$ 開始)代入看看: - **第一次遞迴 $k=2$** $2x=9-\{(2-1)\}$ 因為可以整除所以 `ret+1` - **第二次遞迴 $k=3$** $3x=9-\{(2-1)+(3-1)\}$ 也可以整除所以 `ret+1` 從這邊我們已經可以看出端倪,正好可以解釋程式碼的實做方式: **第8行:** 一開始的初始值是 $N$ ,接著,每次的迴圈中比上一次等號右手邊的值還要再多減去一個 $(k-1)$ ,因此我們便不用每個迴圈都重新計算前面的整數和。 **第9行:** 接著看向等號的左手邊,如果右手邊的值,也就是程式碼中的 $x$ ,能夠整除等號左邊的 $k$ ,也就是程式碼裡面的 $i$ ,我們可以知道這是一個可行解,因此 `ret` 要加一。 **由此我們可以得到 ZZZ= -(k-1)** - **第三次遞迴 $k=4$** $4x=9-\{(2-1)+(3-1)+(4-1)\}$ 在程式碼當中,如果當前的 $x$ 已經小於 $i$ 了,意味著這次遞迴當中等號右手邊的值甚至會比 $i$ 還要小,因此不可能被整除。 --- ### 嘗試更有效率的實做 程式碼本身已經是精簡之後的結果了,以演算法本身來說想不太到比老師的作法更加快速的方法,參考了 [huang-me](https://hackmd.io/@huangme/embedded_quiz5) 同學筆記下老師的建議,分析 `%` 是否能夠被省略。 使用之前的方法,假定: ```cpp= u_int64_t M =((u_int64_t)(__INT64_C(0xFFFFFFFFFFFFFFFF) / i + 1)); if ( x * M <= M-1) ret++; ``` 結果出來時間並沒有比較快,應該是因為還是用到除法的關係。 試過其他方法,結果都超時。 :::info TODO:繼續尋找更快速的方法 :::

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully