sssssssttttttt
    • 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
    contributed by <stevendd543> ### 第 3 週測驗題 #### 第一題 目標 : 以二進位操作完成 square root 的逼近值 * 版本一 : 使用 log2 完成 ```c #include <math.h> int i_sqrt(int N) { int msb = (int) log2(N); int a = 1 << msb; int result = 0; while (a != 0) { if ((result + a) * (result + a) <= N) result += a; a >>= 1; } return result; } ``` 透過 `log2(N)<<1` 先取得[最高有效位](https://zh.wikipedia.org/zh-tw/%E6%9C%80%E9%AB%98%E6%9C%89%E6%95%88%E4%BD%8D),目的是為了不超過 N 下,由大往小找到估計解,可以思考一下為什麼不是從小往大逼近 ? 其實很好理解當你由小往大去疊加你的 `result` 很容易會超過 N,所以比如說要找 $sqrt(56)$ 一定是先找到 $7*7<56$ 再找 $2*2<56-49$,不過這是 10 進位的逼近,二進位一定會有較大誤差,因為依照這個方法其實不會先找到 7~10~ = 0111~2~ 而是會先找到 4~10~ = 100~2~,所以最終估計出來的只能到 (111~2~)^2^ = 49~10~。 * 版本二 : 不使用 log2 完成 ```c while (n > 1) { n >>= 1; msb++; } ``` 其實原本的 log2 只是要用來取得 msb 所以可以不必使用 log2 也能完成。 * 版本三 #### 第二題 ```c static void str_add(char *b, char *a, char *res, size_t size) { int carry = 0; for (int i = 0; i < size; i++) { int tmp = (b[i] - '0') + (a[i] - '0') + carry; carry = tmp / 10; tmp = tmp % 10; res[i] = tmp + '0'; } } ``` 這段程式碼本身在作字串數字相加,但**目標**為了提高效率將其**除法**與**乘法**替換成 bitwise operation,當然精度肯定會減少,但我們只求小數點後第一位是精準即可,因此才有機會使用 bitwise operation 操作。 首先需要思考的事情是**除以10**並不能用 2 的冪表示,換句話說不能以右移來代替除法,因此需要數學證明除數,除了 10 外在什麼樣的範圍內可接受且滿足精度在小數點後一位是精準的。 我先講結論,最後可以透過先將 **tmp 乘以一個倍數 a ,再除以一個 2 的冪** 來代替除法,以數學公式表示 $tmp*\tfrac{a}{2^N} \simeq \tfrac{tmp}{10}$ ,那這裡會好奇原本的除以 10 不能依照這個先乘以倍數在除以 2 的冪嗎 ? 答案是不行因為 2^N^ 本身**不具有 5 的因數**所以不管怎麼除都不會是 $10 \not=\tfrac{2^N}{a}$。 所以這時需要另外找 10 以外的 $x$ 來證明什麼時候能滿足精度的要求。 證明可參考[講義](https://hackmd.io/@sysprog/linux2024-quiz3#%E6%B8%AC%E9%A9%97-2),推導結果 (1) $9.55 \le x \le 10$,因此只要找到$x=\tfrac{2^N}{a}$滿足條件 (1) 的 2 的冪和 a。因此當 $a=13,N=7$ 可以滿足條件。 ```c q = (((tmp >> 3) + (tmp >> 1) + tmp) << 3) >> 7; ``` 回到剛剛的除法替代 $tmp*\tfrac{a}{2^N}=tmp * \tfrac{13}{128} = tmp * \tfrac{2^0+2^2+2^3}{2^7}$ 到這裡還能明白但不知為何需要先將 $13 * tmp$ 除以 8 在乘回來(待釐清),目前是認為因為商的結果都會處在較高位,如果一開始就用左移操作,且原本儲存在 bits 就不是很大就有機會吃掉商的值,為了盡可能避免這狀況發生,所以先除後乘法返還。 #### 第三題 目標 : 實作 log~2~x 的二進位求值 版本一 : 透過右移算子向下取整求出整數對數 ```c int ilog2(int i) { int log = -1; while (i) { i >>= 1; log++; } return log; } ``` 假設 $2^x\le i <2^{x+1},x \in N$, `ilog2` 將會向下取整輸出 $x$。 版本二 : 透過**二分搜尋法**減少計算量 ```c static size_t ilog2(size_t i) { size_t result = 0; while (i >= 65536) { result += 16; i >>= 16; } while (i >= 256) { result += 8; i >>= 8; } while (i >= 16) { result += 4; i >>= 4; } while (i >= 2) { result += 1; i >>= 1; } return result; } ``` 版本三 : 換句話說其實只要找到最高有效位的 bit 就是答案了,因此可以使用`31 - __builtin_clz()` 來完成。 #### 第四題 **Exponential Weight Moving Average** * What is [moving average](https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average) : 那就如字面上的意思,滾動式地計算平均,有方法是固定取 k 個時間點取平均,稱之為 simple moving average,如果有接觸股市就可知道,N 日均線就是一種 SMA。也有方法是採用累加的方式來計算平均,就像 Cumulative average 每當有新資料,就將原本的平均展開並加上新資料來取平均。那 Exponential Weight Moving Average 與這些差異在於,多了權重的參與,讓當下的資料與過去所有資料的平均有權重上之分,這裡的 Exponential 就是過去的資料重要性會隨著越舊而指數下降。 原理: >It maintains a structure housing the EWMA parameters alongside a scaled internal representation of the average value, aimed at minimizing rounding errors. 可以看到程式碼中提到,使用了 structure 儲存 EWMA 參數,其中參數包含了 factor、weight、internal,(1) 這裡的 factor 強調是為了 `minimizing rounding errors` 也就是定點數的 scaling factor ,(2) 而 weight 則是以 2 的冪來表示,但要注意這裡的 weight 並不是 $\alpha = 2^{-n}$ , 而是透過 log 取得 $weight = n$,這是為了 bitwise operation 而儲存的形式,因此就可以透過右移 weight 個 bits 來達到乘以 2^-n^ 操作。(3) 最後 internal 全名為 internal representation 簡單翻譯就是內部表達式,換句話說因為這是定點數操作,所以當你乘上 factor 轉換成定點數後,這些平均結果都會以**內部表示式**來呈現,也就是**定點數的呈現方式**,當你要透過 `unsigned long ewma_read(const struct ewma *avg)` 讀取真正的值才會利用 左移 factor 個 bits 來返還真實值。 特別注意到 `ewma_add` 這個計算 EWMA 的函式,因為我們知道 EWMA 公式為$S_t=\alpha Y_t+(1-\alpha) S_{t-1}$,先將其乘以權重 `avg->weight` 假設為$\bar\alpha$,$\bar\alpha \alpha=1$, $\bar\alpha S_t=\bar\alpha\alpha Y_t+\bar\alpha(1-\alpha) S_{t-1}=>\bar\alpha S_t= Y_t+\bar\alpha S_{t-1}-S_{t-1}$ 最後再把結果 `>>avg->weight` 回來即可。 ```c struct ewma *ewma_add(struct ewma *avg, unsigned long val) { avg->internal = avg->internal ? (((avg->internal << avg->weight) - avg->internal) + (val << avg->factor)) >> avg->weight : (val << avg->factor); return avg; } ``` #### 第五題 ```c int ceil_ilog2(uint32_t x) { uint32_t r, shift; x--; r = (x > 0xFFFF) << 4; x >>= r; shift = (x > 0xFF) << 3; x >>= shift; r |= shift; shift = (x > 0xF) << 2; x >>= shift; r |= shift; shift = (x > 0x3) << 1; x >>= shift; return (r | shift | x > 1) + 1; } ``` 這段程式碼跟測驗三同樣使用的是**二分搜尋法**,只是以不同方式表達, ` while (i >= 65536)` 對應到 `r = (x > 0xFFFF) << 4` 這裡不用 while 的原因是輸入只有 32bits,不會重複執行。`result += 16` 對應到 `r |= shift` ,然後 `i >>= 16` 對應到 `x >>= shift`。 #### 延伸問題 如果 x=0 ,在第一步就會發生向下溢位,出來的結果就會不正確,因此要確保再 x 等於 0 的時候不作減法`x += !!x`,不過這個在沒有明確定義輸入錯誤的處理,只能避免溢位,答案仍然會是錯誤的。如果可接受溢位,也可在 `x--` 後添加 `x += (x > (x+1))`。 額外提及一點還有 x 型態為 `uint32_t` ,因此 `x > 0xFFFF` 並不會發生,因此此條件永遠不會成立,不過如果考量到通用性,確實可以將其程式碼保留。 ### 第 4 週測驗題 #### 第一題 ```c int totalHammingDistance(int* nums, int numsSize) { int total = 0;; for (int i = 0;i < numsSize;i++) for (int j = 0; j < numsSize;j++) total += __builtin_popcount(nums[i] ^ nums[j]); return total >> 1; } ``` 計算每對$HammingDistance(nums[i],nums[j])$,但因為每一對都會出現兩次因此最後要除以 2。 #### 第二題 n = popcount(n & 0x55555555) - popcount(n & 0xAAAAAAAA) #### 第三題

    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