- 고정 소수점이란 소수점을 사용하여 고정된 자리수의 소수를 나타내는 것이다. 한정된 메모리에서 부동소수점 방식보다 좁은 범위의 수만 나타낼 수 있다.
- 컴퓨터에서는 이진법 혹은 십진법을 사용하여 고정소수점을 사용한다.
- 맨앞자리를 부호 비트로 보통 사용하고, 0일경우 양수, 음일 경우 1임을 나타낸다.
- 소수점을 미리 정해 두며 정수부의 경우 뒤에서 부터, 소수부의 경우 앞에서 부터 수를 채우고 남은 수들은 0으로 채운다.
- 부동 소수점의 경우 일정한 유효숫자를 보장하지만 고정 소수점 방식의 경우 소수점을 미리 정해 놓기에 연산시에 값의 손실이 쉽게 생긴다. 그러나 덧셈/뺄셈 연산은 부동 소수점보다 간편하다는 장점이 있다.
- 표현 가능한 실수의 범위와 정밀도가 제한적이기에 현재는 실질적으로 잘 사용하지 않는다.
### 1. Brief information about our values
* fx_s4716
...
...
@@ -18,10 +25,15 @@
*```fx``` -> fixed point(고정 소수점 방식 사용)
*```s``` -> signed(부호 1비트 사용)
*```4716``` -> 정수부 47비트, 소수부 16비트 사용
* minimum : -140,737,488,355,328 (-2^63/2^16)
* maximum : 140,737,488,355,327.9999847412109375 (2^63-1/2^16)
* resolution : 0.0000152587890625 (1/2^16)
### 2. List of functions ( All functions are based on fixed point number operation. )
- 사칙연산 함수(매크로)
...
...
@@ -33,6 +45,8 @@
| fx_s4716_double_mul(a, b) | a와 b의 곱 연산이며 각 값을 먼저 double형으로 변환한 후에 연산을 수행하고 그에 따라 나온 double형 결과값을 다시 fx형으로 재변환을 해주는 연산이다. |
| fx_s4716_double_div(a, b) | a와 b의 나누기 연산이며 곱셉과 마찬가지로 double형으로 변환 후 값을 계산하고 다시 재변환하는 연산이다. |
* 그외 연산 함수(매크로)및 상수
| 함수(매크로)명 | 설명 |
...
...
@@ -45,6 +59,8 @@
| double_to_fx(a) | double형에서 고정소수점으로 변환하는 매크로로 위의 연산과 반대로 2^16을 곱해준다. |
| fx_sine(a) | sin(a)값을 고정소수점으로 변환하는 매크로로 math.h의 sin함수를 사용하여 변환을 진행한다. |
### 3. Make Build
- Makefile은 기본적으로 Target, Dependency, Recipe 등에 대한 Rules로 이루어져 있다.
...
...
@@ -90,8 +106,12 @@
- 이번 프로젝트에서는 2^n을 곱하는 것이 아닌 쉬프트연산을 사용하여 >>, <<으로 곱이나 나눗셈을 표현하였다. 이를 통해 좀 더 직관적으로 고정 소수점을 표현하였고 이에따라 연산의 결과값이 정수부가 47bit를 넘는다면 overflow가 발생할 것이고 소수부가 16bit를 넘는다면 underflow가 발생할 것임을 알 수 있다.
- 처음 위의 Project #1에서는 double형을 사용하여 연산을 진행함으로써 만약 값이 크다면 그 큰 값을 표현하기에 double형이 작아 수의 손실이 일어날 수 있다. 따라서 Project #2에서는 long long형을 사용해 연산을 함으로써 div나 mul과 값이 큰 값이 나오는 연산에서도 최대한 수의 손실을 줄일 수 있게 하였다.
### 2. Added functions
- MUL
...
...
@@ -114,6 +134,8 @@
위의 MUL2보다는 손실이 크지만 속도는 빠른 연산이다. 4 쉬프트 연산으로 유효범위를 적당히 늘려 MUL1보다는 손실이 적고 속도는 느리다. MUL1과 MUL2의 사이 수준의 연산이라고 생각하면 된다.
- DIV
-```
...
...
@@ -126,7 +148,7 @@
#define FX_S4716_LONGLONG_DIV2(a, b) (((a << 8) / (b)) << 8)
```
값을 미리 나누었기에 overlfow확률이 DIV1보다는 크지만 작은편이다
값을 미리 나누었기에 overlfow확률이 DIV1보다는 크지만 작은편이다.
-```
#define FX_S4716_LONGLONG_DIV3(a, b) (((a << 12) / (b)) << 4)
...
...
@@ -134,6 +156,8 @@
위의 DIV1과 DIV2 연산의 중간 연산이라고 생각하면 됩니다.
- sin
```
...
...
@@ -148,6 +172,8 @@
sin함수의 경우 그전 프로젝트에서는 math.h에 있는 기존 라이브러리 함수를 이용했던 반면에 이번 프로젝트에서는 테이블을 만들어 들어오는 값에 대응하는 고정소수점 값을 넣어주게 만들었다. 위의 테이블에서 90이 넘게 92로 범위를 설정한 것은 배열의 크기가 91이므로 편리하게 사용하기 위해 설정해주었다.
```
fx_s4716 fx_s4716_longlong_sin(fx_s4716 a){
long long quotient, remain, result;
...
...
@@ -162,21 +188,35 @@
```
위의 함수에서 사인함수의 각도가 90을 넘어갈 경우에 그 각도를 다시 계산해주는 연산을 넣어주어서 90이 넘어가는 a값에 해당하는 사인값도 테이블에 매칭되서 결과값을 반환하게 만들어주었다.
위의 함수에서 사인함수의 각도가 90을 넘어갈 경우에 그 각도를 몫과 나머지 계산을 통해서 90이 넘어가는 a값에 해당하는 값을 변환시켜줌으로써 사인값도 테이블에 매칭되서 결과값을 반환하게 만들어주었다.
### 3. Performance Test(Using GNU gprof)
-```
sudo apt-get install gcc-multilib
```
위의 명령어를 이용해 프로그램 성능 측정을 위한 프로그램을 설치할 수 있다.
### 3. Performance Test
-```
gcc -pg test.c <컴파일 필요한 파일들> -m64, -m32
```
위의 명령어를 이용해 `-m64`의 경우 64비트로 컴파일이 가능하고 `-m32`의 경우 32비트로 파일을 컴파일이 가능하다. 컴파일된 비트수에 따라 double형과 longlong형의 속도가 달라진다. `-pg`옵션을 붙여줌으로써 gprof 성능분석을 할 수 있게 한다.
위의 명령어를 이용해 `-m64`의 경우 64비트로 컴파일이 가능하고 `-m32`의 경우 32비트로 파일을 컴파일이 가능하다. 컴파일된 비트수에 따라 double형과 longlong형의 속도가 달라진다. 또한 operator 연산(사칙 연산)과 쉬프트 연산의 속도 또한 달라진다. `-pg`옵션을 붙여줌으로써 프로파일링 대상이 되는 파일에 대해 gprof 성능분석을 할 수 있게 한다.
-```
gprof
```
gprof명령어를 사용해 프로그램의 성능 측정을 할 수 있는데 각 함수의 속도와 호출 횟수등을 확인할 수 있다. `gmon.out`파일에 성능 측정의 내용이 들어가며 리다이렉션을 통해 파일을 기록해줄 수 있다.
gprof명령어를 사용해 프로그램의 성능 측정을 할 수 있는데 각 함수의 속도와 호출 횟수등을 확인할 수 있다. 이 프로젝트에선 쉬프트 연산과 operator 연산이 같이 섞여 있어 속도와 정확성을 비교하기 용이한 프로그램이다.`gmon.out`파일에 성능 측정의 내용이 들어가며 리다이렉션을 통해 파일을 기록해줄 수 있다.
- 정확도 비교
...
...
@@ -186,6 +226,8 @@
이를 통해 어느정도의 shift를 미리 하는 것이 유효숫자의 범위가 커져 손실이 줄어듬을 알 수 있다.
- 속도 비교
- 32비트 컴파일환경 곱하기 연산
...
...
@@ -198,7 +240,9 @@

64비트 환경의 경우 operator연산이 빨라 1->2->3순으로 속도순이 정해진다.
64비트 환경의 경우 operator연산이 빨라 위의 32비트 환경과 다르게 곱하기 연산의 값이 큰 것과 상관없이 1->2->3순으로 속도순이 정해진다.
- 32비트 컴파일환경 나누기 연산
...
...
@@ -208,4 +252,4 @@

DIV연산에서 첫 값에 대한 쉬프트 연산의 크기 순으로 속도가 잘 나오는 것을 알 수 있다.
DIV연산에서 첫 값에 대한 쉬프트 연산의 크기 순으로 속도가 잘 나오는 것을 알 수 있다. DIV1의 경우 16 DIV2의 경우 8 DIV3의 경우 12 만큼 왼쪽 쉬프트를 해주었기에 1 -> 3 -> 2순이다.