Skip to content
Snippets Groups Projects
Commit a4adab0a authored by 김영진's avatar 김영진
Browse files

Update README

parent cdccd9c0
No related branches found
No related tags found
No related merge requests found
......@@ -2,11 +2,19 @@
## Team 6 - Project # 1 ( Fixed Point Number )
### 0. What is fixed point?
- 고정 소수점이란 소수점을 사용하여 고정된 자리수의 소수를 나타내는 것이다. 한정된 메모리에서 부동소수점 방식보다 좁은 범위의 수만 나타낼 수 있다.
- 컴퓨터에서는 이진법 혹은 십진법을 사용하여 고정소수점을 사용한다.
- 맨앞자리를 부호 비트로 보통 사용하고, 0일경우 양수, 음일 경우 1임을 나타낸다.
- 소수점을 미리 정해 두며 정수부의 경우 뒤에서 부터, 소수부의 경우 앞에서 부터 수를 채우고 남은 수들은 0으로 채운다.
- 부동 소수점의 경우 일정한 유효숫자를 보장하지만 고정 소수점 방식의 경우 소수점을 미리 정해 놓기에 연산시에 값의 손실이 쉽게 생긴다. 그러나 덧셈/뺄셈 연산은 부동 소수점보다 간편하다는 장점이 있다.
- 표현 가능한 실수의 범위와 정밀도가 제한적이기에 현재는 실질적으로 잘 사용하지 않는다.
### 1. Brief information about our values
* fx_s4716
![고정소수점](https://user-images.githubusercontent.com/54850435/89747372-7d2c7980-daf9-11ea-8fd1-ea83b9d46ffc.png)
* ```fx``` -> fixed point(고정 소수점 방식 사용)
* ```s``` -> signed(부호 1비트 사용)
* ```4716``` -> 정수부 47비트, 소수부 16비트 사용
......@@ -16,17 +24,26 @@
### 2. List of functions ( All functions are based on fixed point number operation. )
* fx_s4716_double_add(a, b) : a와 b의 합 연산
* fx_s4716_double_sub(a, b) : a와 b의 차 연산
* fx_s4716_double_mul(a, b) : a와 b의 곱 연산
* fx_s4716_double_div(a, b) : a와 b의 나누기 연산
* fx_s4716_double_sqrt(a) : a의 제곱근 연산
* fx_s4716_double_pow(a) : a의 제곱 연산
* fx_pi : PI값을 고정소수점으로 변환
* fx_inv_pi : 1/PI값을 고정소수점으로 변환
* fx_to_double(a) : 고정소수점에서 double형으로 변환
* double_to_fx(a) : double형에서 고정소수점으로 변환
* fx_sine(a) : sin(a)값을 고정소수점으로 변환
- 사칙연산 함수(매크로)
| 함수(매크로)명 | 설명 |
| ------------------------- | ------------------------------------------------------------ |
| fx_s4716_double_add(a, b) | a와 b의 합 연산이며 다른 추가 연산없이 덧셈을 수행한다. |
| fx_s4716_double_sub(a, b) | a와 b의 차 연산이며 덧셈과 마찬가지로 바로 두 개의 값의 차를 구한다. |
| fx_s4716_double_mul(a, b) | a와 b의 곱 연산이며 각 값을 먼저 double형으로 변환한 후에 연산을 수행하고 그에 따라 나온 double형 결과값을 다시 fx형으로 재변환을 해주는 연산이다. |
| fx_s4716_double_div(a, b) | a와 b의 나누기 연산이며 곱셉과 마찬가지로 double형으로 변환 후 값을 계산하고 다시 재변환하는 연산이다. |
* 그외 연산 함수(매크로)및 상수
| 함수(매크로)명 | 설명 |
| ----------------------- | ------------------------------------------------------------ |
| fx_s4716_double_sqrt(a) | a의 제곱근 연산이며 a값을 fx형으로 변환을 해주고 math.h의 sqrt함수를 사용해 값을 계산 후 2^8으로 나누어준다. |
| fx_s4716_double_pow(a) | a의 제곱 연산이며 a값을 pow함수를 사용해 제곱을 해주고 2^16으로 나누어 fx형으로 표현하는 연산이다. |
| fx_pi | PI값을 고정소수점으로 변환하는 매크로로 math.h의 M_PI값을 FX형으로 변환하여 값을 표현한다. |
| fx_inv_pi | 1/PI값을 고정소수점으로 변환하는 매크로로 1/M_PI값으로 위의 연산과 동일하게 진행한다. |
| fx_to_double(a) | 고정소수점에서 double형으로 변환하는 매크로로 2^16으로 나누어준다.(소수부 16비트 표현) |
| double_to_fx(a) | double형에서 고정소수점으로 변환하는 매크로로 위의 연산과 반대로 2^16을 곱해준다. |
| fx_sine(a) | sin(a)값을 고정소수점으로 변환하는 매크로로 math.h의 sin함수를 사용하여 변환을 진행한다. |
### 3. Make Build
......@@ -38,6 +55,7 @@
* Target : 빌드 대상 이름.
* Dependencies : 빌드 대상이 의존하는 Target이나 파일 목록.
* Recipe : 빌드 대상을 생성하는 명령. 무조건 ```tab```을 넣어주어야 한다.
- Macro, Variable 이용
1. SRCS : 소스 파일들의 이름을 적는다.
......@@ -46,10 +64,148 @@
4. CFLAGS : 컴파일에 필요한 각종 옵션을 추가한다.
5. $@ : 현재 Target 파일명
6. $^ : 현재 모든 dependency 파일들의 명단
- test.c, fx_s4716_double.c 와 fx_s4716_double.h를 make 명령어 하나로 자동으로 빌드하게 해줌
- gcc 컴파일러를 사용하였으며 mytest 실행파일과 각 c파일의 목적파일을 자동으로 생성
* -lm : math.h 라이브러리 추가
- make clean을 통해 실행파일과 목적파일을 삭제할 수 있음
- make dep를 통해 각 파일의 헤더파일을 미리 연결해줌
- make clean 명령어를 통해 자신이 지우고 싶은 실행파일과 목적파일을 정하여 삭제할 수 있음
- make dep 명령어를 통해 각 파일의 헤더파일을 자동으로 미리 연결해줌
### 4. Run Program
- `make dep `명령어를 사용해 헤더파일을 연결해준다.
- `make` 명령어를 사용해 자동으로 프로젝트를 빌드해준다.
- 지정된 파일을 실행하고 연산을 원하는 값을 두개 넣어준다.
- 두개의 값을 이용한 모든 연산을 출력한다.
## Project #2 (Using long long type & Performance Test)
### 1. Using shift operation & long long type
- 이번 프로젝트에서는 2^n을 곱하는 것이 아닌 쉬프트연산을 사용하여 >>, <<으로 곱이나 나눗셈을 표현하였다. 이를 통해 좀 더 직관적으로 고정 소수점을 표현하였고 이에따라 연산의 결과값이 정수부가 47bit를 넘는다면 overflow가 발생할 것이고 소수부가 16bit를 넘는다면 underflow가 발생할 것임을 알 수 있다.
- 처음 위의 Project #1에서는 double형을 사용하여 연산을 진행함으로써 만약 값이 크다면 그 큰 값을 표현하기에 double형이 작아 수의 손실이 일어날 수 있다. 따라서 Project #2에서는 long long형을 사용해 연산을 함으로써 div나 mul과 값이 큰 값이 나오는 연산에서도 최대한 수의 손실을 줄일 수 있게 하였다.
### 2. Added functions
- MUL
- ```
#define FX_S4716_LONGLONG_MUL1(a, b) (((a) * (b)) >> 16)
```
연산의 개수가 적어 속도는 빠르지만 앞의 곱하기 연산에서 값이 커질 경우 overflow가 발생하여 값이 손실되기 쉽다.
- ```
#define FX_S4716_LONGLONG_MUL2(a, b) ((a >> 8) * (b >> 8))
```
각 값의 정수부를 미리 8 쉬프트 연산을 통해 늘림으로서 위의 MUL1 보다는 느리지만 유효범위가 늘어나서 값의 손실이 적다. 계산 값이 MUL1보단 크지 않아 overflow는 잘 발생하지 않지만 작은 값의 경우 오히려 underflow가 발생할 수 있다.
- ```
#define FX_S4716_LONGLONG_MUL3(a, b) (((a >> 4) * (b >> 4)) >> 8)
```
위의 MUL2보다는 손실이 크지만 속도는 빠른 연산이다. 4 쉬프트 연산으로 유효범위를 적당히 늘려 MUL1보다는 손실이 적고 속도는 느리다. MUL1과 MUL2의 사이 수준의 연산이라고 생각하면 된다.
- DIV
- ```
#define FX_S4716_LONGLONG_DIV1(a, b) ((a << 16) / (b))
```
연산의 갯수가 적어 가장 빠른 div연산이다. 왼쪽 쉬프트로 인해 소수부가 늘어나 underflow가 발생할 수 있다.
- ```
#define FX_S4716_LONGLONG_DIV2(a, b) (((a << 8) / (b)) << 8)
```
값을 미리 나누었기에 overlfow확률이 DIV1보다는 크지만 작은편이다
- ```
#define FX_S4716_LONGLONG_DIV3(a, b) (((a << 12) / (b)) << 4)
```
위의 DIV1과 DIV2 연산의 중간 연산이라고 생각하면 됩니다.
- sin
```
const fx_s4716 sinTable[92]=
{
0,1143,2287,3429,4571,5711,6850,7986,9120,10252,11380,12504,13625,14742,15854,16961,18064,19160,20251,21336,22414,23486,24550,25606,26655, 27696,28729,29752,
30767,31772,32768,33753,34728,35693,36647,37589,38521,39440,40347,41243,42125,42995,43852,44695,45525,46340,47142, 47929,48702,49460,50203,50931,51643,52339,
53019,53683,54331,54963,55577,56175,56755,57319,57864,58393,58903,59395,59870,60326,60763, 61183,61583,61965,62328,62672,62997,63302,63589,63856,64103,64331,
64540,64729,64898,65047,65176,65286,65376,65446,65496,65526,65536,65526
};
```
sin함수의 경우 그전 프로젝트에서는 math.h에 있는 기존 라이브러리 함수를 이용했던 반면에 이번 프로젝트에서는 테이블을 만들어 들어오는 값에 대응하는 고정소수점 값을 넣어주게 만들었다. 위의 테이블에서 90이 넘게 92로 범위를 설정한 것은 배열의 크기가 91이므로 편리하게 사용하기 위해 설정해주었다.
```
fx_s4716 fx_s4716_longlong_sin(fx_s4716 a){
long long quotient, remain, result;
remain=a%180;
if(remain>90)
remain=180-remain;
quotient=a/180;
result=(sinTable[remain])*(pow(-1,quotient));
return fx_to_longlong(result);
}
```
위의 함수에서 사인함수의 각도가 90을 넘어갈 경우에 그 각도를 다시 계산해주는 연산을 넣어주어서 90이 넘어가는 a값에 해당하는 사인값도 테이블에 매칭되서 결과값을 반환하게 만들어주었다.
### 3. Performance Test
- ```
gcc -pg test.c <컴파일 필요한 파일들> -m64, -m32
```
위의 명령어를 이용해 `-m64`의 경우 64비트로 컴파일이 가능하고 `-m32`의 경우 32비트로 파일을 컴파일이 가능하다. 컴파일된 비트수에 따라 double형과 longlong형의 속도가 달라진다. `-pg`옵션을 붙여줌으로써 gprof 성능분석을 할 수 있게 한다.
- ```
gprof
```
gprof명령어를 사용해 프로그램의 성능 측정을 할 수 있는데 각 함수의 속도와 호출 횟수등을 확인할 수 있다. `gmon.out`파일에 성능 측정의 내용이 들어가며 리다이렉션을 통해 파일을 기록해줄 수 있다.
- 정확도 비교
- 64비트 컴파일
![64r](C:\Users\young\Desktop\Practice\fx_s4716\images\64r.PNG)
이를 통해 어느정도의 shift를 미리 하는 것이 유효숫자의 범위가 커져 손실이 줄어듬을 알 수 있다.
- 속도 비교
- 32비트 컴파일환경 곱하기 연산
![32m](C:\Users\young\Desktop\Practice\fx_s4716\images\32m.PNG)
32비트 환경의 경우 operator 곱하기 연산의 속도가 매우 느려서 큰 값끼리 곱할 수록 속도가 느려져서 2 -> 3 ->1순으로 속도의 순위가 정해진다.
- 64비트 컴파일환경 곱하기 연산
![64m](C:\Users\young\Desktop\Practice\fx_s4716\images\64m.PNG)
64비트 환경의 경우 operator연산이 빨라 1->2->3순으로 속도순이 정해진다.
- 32비트 컴파일환경 나누기 연산
![32d](C:\Users\young\Desktop\Practice\fx_s4716\images\32d.PNG)
- 64비트 컴파일환경 나누기 연산
![64d](C:\Users\young\Desktop\Practice\fx_s4716\images\64d.PNG)
DIV연산에서 첫 값에 대한 쉬프트 연산의 크기 순으로 속도가 잘 나오는 것을 알 수 있다.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment