# HW03 參考答案 ## 3.1 Circle Functions Credit: 41247006S 張呈義 ```c= #include <stdio.h> #include <stdint.h> #include <math.h> static double radius = -1.0; static uint8_t is_radius_set = 0; int32_t set_radius( double r){ if(r <= 0) return -1; else{ is_radius_set = 1; radius = r; return 0; } } double get_circle_circumference(){ if(is_radius_set) return (double) 2 * radius * M_PI; else return -1.0; } double get_circle_area(){ if(is_radius_set) return (double) radius * radius * M_PI; else return -1.0; } double get_tangent_area( double x ){ double y = 0, m_point = 0, m_tangent = 0, b = 0; double area = 0; x = fabs(x); //fabs: absolute value for double if((x >= radius)) return -1; if(is_radius_set){ y = sqrt(radius*radius - x*x); m_point = y / fabs(x); m_tangent = -(1 / m_point); //tangent: y = m_tangent*x + b; b = y - m_tangent*x; area = fabs(b) * fabs(-b / m_tangent) / 2; if(m_tangent == 0) return -1; return area; } else return -1; } double get_inner_regular_polygon_area( int32_t n ){ if(n < 3) return -1; long double alpha = (2*M_PI) / (long double) n;//the angles of split triangles; long double area = 0; if(is_radius_set){ area = n * (radius * radius * sin(alpha)) / 2; return (double) area; } else return -1; } double get_outer_regular_polygon_area( int32_t n ){ if(n < 3) return -1; long double alpha = (2*M_PI) / (long double) n, beta = alpha / 2; long double side = 0, area = 0; //the angles of split triangles; beta = alpha / 2. if(is_radius_set){ side = radius / (cos(beta)); area = n * (side * side * sin(alpha)) / 2; return (double) area; } else return -1; } ``` ## 3.2 Control Game Character mycontrol.h ```c= #pragma once #include <stdio.h> #include <stdint.h> #include <stdbool.h> #include <math.h> // Setup the initial position to (x,y) and the moving direction. // a is the angle counterclockwise from x axis. void initialize( double x, double y, double a); // From the current , move forward length with the givendirection. // If the initial position is not set, return -1. int32_t forward( double length ); // From the current direction , turn clockwise/counterclockwisex. // If the initial position is not set, return -1. int32_t clock_turn( double x ); int32_t counterclock_turn( double x ); // Print the current location and the direction. // The print format is "position: (x,y), angle: a". // a is the angle counterclockwise from x axis and 0 <= a <= 2 pi // If the initial position is not set, return -1. int32_t print(); ``` mycontrol.c ```c= #include "mycontrol.h" static double character_x, character_y, character_a; static bool initialized = false; void initialize( double x, double y, double a) { character_x = x; character_y = y; character_a = a; initialized = true; } int32_t forward( double length ) { if (!initialized) { return -1; } character_x += length * cos(character_a); character_y += length * sin(character_a); return 0; } int32_t clock_turn( double x ) { if (!initialized) { return -1; } character_a -= x; return 0; } int32_t counterclock_turn( double x ) { if (!initialized) { return -1; } character_a += x; return 0; } int32_t print() { if (!initialized) { return -1; } while (character_a >= 2 * M_PI) { character_a -= 2 * M_PI; } while (character_a < 0) { character_a += 2 * M_PI; } printf("position: (%.2lf,%.2lf), angle: %.2lf\n", round(character_x * 100.0)/100.0, round(character_y * 100.0)/100.0, round(character_a / M_PI * 100.0)/100.0); return 0; } ``` ## 3.3 Binary Form Credit: 41247034S 伍O宇 ```c= #include <stdio.h> #include <stdint.h> #include <math.h> void BinaryForm(int64_t num); int main(){ int64_t input=0; printf("Please enter the number: "); scanf("%ld", &input); //input error if(input>2147483647||input<-2147483648){ printf("The input number should be a signed 32-bit integer\n"); return 0; } BinaryForm(input); return 0; } void BinaryForm(int64_t num){ if(num<0){ num=4294967296+num; } static int64_t digit=32; int64_t out=0; if(digit>0){ if(digit%8==0 && digit!=32){ printf(" "); } out=num/pow(2,digit-1); printf("%ld",out); num%=(int64_t)pow(2,digit-1); digit--; BinaryForm(num); }else{ printf("\n"); return; } } ``` ## 3.4 Tower of Hanoi Credit: 41247004S 廖O翔 ```c= // hw0304.h #pragma once #include <stdint.h> #include <stdio.h> // from a to b, c is buf void hanoi(int32_t disk, int8_t a, int8_t b, int8_t c); ``` ```c= // hw0304.c #include "hw0304.h" #include <stdint.h> #include <stdio.h> int main(int argc, char const *argv[]) { int32_t disk = 0; double input = 0; printf("Please enter the disk number (2-20): "); scanf("%lf", &input); if (input - (int)(input) != 0) { printf("wrong input.\n"); return 1; } disk = (int)(input); if (disk < 2 || disk > 20) { printf("wrong input.\n"); return 1; } hanoi(disk, 1, 2, 3); return 0; } ``` ```c= // hw0304-1.c #include <stdint.h> #include <stdio.h> #include "hw0304.h" void hanoi(int32_t disk, int8_t a, int8_t b, int8_t c) { /* | | | ------- A B C */ if (disk == 1) { printf("move disk %d to rod %d\n", disk, b); } else { hanoi(disk - 1, a, c, b); printf("move disk %d to rod %d\n", disk, b); hanoi(disk - 1, c, b, a); } } ``` ```c= // hw0304-2.c #include <math.h> #include <stdint.h> #include <stdio.h> #include "hw0304.h" void hanoi(int32_t disk, int8_t a, int8_t b, int8_t c) { int32_t disk_p = 0, times = 0, lo2 = 0, number = 0, rod = 0, pow_2_disk = 1 << disk, breaker = 0, ii = 0; double count = 0; for (int32_t i = 1; i < pow_2_disk; i++) { if (i % 2) { disk_p = 1; times = (i + 1) / 2; } else { ii = i; while (ii % 2 != 1) { ii /= 2; disk_p++; } times = (i + pow(2, disk_p - 1)) / pow(2, disk_p); } times = (int)(times) % 3; if (disk % 2 == 0) { if (disk_p % 2 == 1) { if (times % 3 == 1) { rod = 3; } else if (times % 3 == 2) { rod = 2; } else { rod = 1; } } else { if (times % 3 == 1) { rod = 2; } else if (times % 3 == 2) { rod = 3; } else { rod = 1; } } } else { if (disk_p % 2 == 1) { if (times % 3 == 1) { rod = 2; } else if (times % 3 == 2) { rod = 3; } else { rod = 1; } } else { if (times % 3 == 1) { rod = 3; } else if (times % 3 == 2) { rod = 2; } else { rod = 1; } } } printf("move disk %d to rod %d\n", disk_p, rod); } } ``` ```makefile= # Makefile, relevant-part only all: gcc -c hw0304-1.c -o hw0304-1.o gcc -c hw0304-2.c -o hw0304-2.o gcc hw0304.c hw0304-1.o -o hw0304-1 -lm gcc hw0304.c hw0304-2.o -o hw0304-2 -lm ``` ## 3.5 How to roll your dice SE (Simple Edition)? 本題有非常多有創意的同學不僅把骰子的程式寫出來,還又寫了超帥的介面或超級好玩的遊戲! 我就不提供解答了,歡迎去 Discord 伺服器分享彼此的程式分享給大家! 某些人的真的超好玩 你們好棒 ## 3.6 Bonus: diff and patch Credit: 41147054S 廖O嫺 我們可以使用 Linux patch命令來修改或更新文件。具體方式如下: - 1. 首先可以使用cat指令查看升級文件與原文件之內容,如下: ```bash $ cat myfile1 #查看myfile1 This is myfile1. $ cat myfile2 #查看myfile2 This is myfile2. ``` - 2. diff指令在於比較檔案的不同。若兩個檔案的內容相同, diff 指令不會有任何輸出; 如果兩個檔案有不同的地方, diff 便會將不同的行列出,如下: ```bash $ diff myfile1 myfile2 #比較兩個檔案 1c1 <This is myfile1. --- >This is myfile2. ``` - 3. 將比較的結果保存至 myfile.patch 文件中,如下: ```bash $ diff myfile1 myfile2 > myfile.patch #符號 > 表示將 ``` 該符號左邊的文件內容寫入右邊所指向的文件中,反之亦然。 ```bash $ cat myfile.patch #查看myfile.patch 1c1 <This is myfile1. --- >This is myfile2. ``` - 4. 將補丁(patch)寫入原文件,如下: ```bash $ patch -p0 myfile1 myfile.patch patching file myfile1 ``` - 5. 於是乎我們可以得到文件被修改後的內容,如下: ```bash $ cat myfile1 #查看myfile1 This is myfile2.#此時myfile1已被修改成與myfile2相同的內容 ``` ## 3.7 Bonus: Plagiarism Detection Credit: 41044028S 黃O耘 ``` 我想用香水來做比喻 code,Moss 就是要抓相似的香水 想象一下,如果老師手裡有一堆學生的 coding 作業,他想知道這些作業里有沒有人是抄襲別人的。但是,如果學生們只是簡單地把別人的 code 複製過來,然後改改變量名或者加點注釋,這樣肉眼看起來 code 就不一樣了,老師很難發現真相。 這時候 Moss 就派上用場了。它不是去看 code 長得像不像,而是通過一種特別的方法來「嗅」code,找出 code 的獨特「味道」。就像是不同的香水即使瓶子換了,味道還是能被辨認出來一樣。 Moss 的做法是這樣的: * 清潔:首先,Moss 會把 code 里的空格、注釋這些看起來不重要的東西都去掉,就像洗掉香水瓶上的標籤一樣。 * 提取「香味」:然後,它會從剩下的 code 中提取一些特別的標記,這些標記就像是香水的味道成分,可以代表這段 code 的特點。 * 挑選特徵:接下來,Moss 會用一種叫「winnowing」的方法,從這些標記中挑出最能代表 code 特色的幾個,就像是挑選出最有代表性的香味成分。 * 比較:有了這些特徵,Moss 就可以把不同學生的 code 放在一起比較了,看看誰和誰的「香味」特別相似。 * 出結果:最後,Moss 會告訴老師,哪些學生的作業里有類似的「香味」,可能是抄襲的。 這個方法很厲害,因為即使學生們改變了 code 的樣子,Moss 還是能通過這些「香味」成分找到相似之處。但是,如果一個學生把抄來的 code 改得面目全非,或者用一個完全不同的方法來寫相同的功能,Moss 就可能找不到了。就像是如果一個香水的味道成分被改得太多,你就認不出它是不是原來那個香水了。 ``` Credit: 60840031S 鄭O文 ``` 參考文獻來源: http://theory.stanford.edu/~aiken/publications/papers/sigmod03.pdf (1)摘要 此篇文獻敘述關於文件指紋識別技術的應用與重要性,特別是在識別大 量文檔集中的部分複製時,如何精確地識別文件複製的情況,即使是文件的 一小部分也能被檢測出來。 (2)核心檢測概念 K-gram 哈希化: 文檔被分解成 k 個字符長度的子串(k-grams),對於文 檔中的每個 k-gram,使用哈希函數計算出一個哈希值。 選擇性指紋: 算法接下來並不會使用所有的哈希值作為文檔的指紋。而 是通過一種叫做"winnowing"的方法來選取哈希值的子集作為指紋。這個過 程包含了對相鄰哈希值的分析,選取這些值中的最小者,通常是在一個窗口 範圍內最小的哈希值。 保持局部最小值: 在選取指紋的過程中,winnowing 算法會選擇局部範 圍內的最小哈希值。這確保了當文檔發生局部修改時,其指紋的絕大部分仍 然是不變的,這樣就可以容忍一些改動,同時依舊能夠檢測到文檔之間的相 似性。 抗雜訊和冗餘: 由於 winnowing 選取的是局部最小值,因此對於常見的 和無意義的 k-gram(例如頻繁出現的單詞或者空格)不太可能被選為指 紋,這樣可以避免這些普遍存在的元素導致的雜訊。 有效性和效率: 所產生的指紋集合不僅反映了文檔的獨特特徵,而且由 於其節省空間的特性和局部最小化過程,算法是高效的,這使得它特別適合 於大規模的文檔比對工作,例如抄襲檢測。 ``` > hash:一般來說會用「雜湊」一詞,但對岸較常用「哈希」 > local:此例會用「局部」一詞,用「本地」比較奇怪 > winnowing:在此為演算法專有名詞,盡量用原文,有些人用了「風選」一詞勉強猜得到