diff --git a/Makefile b/Makefile index 96c6c65720bf75766540e722119773e9c5901f56..784a7f4158727c695b059a7ee56b7cf127e7d573 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,19 @@ -SRCS := test.c fx_s1516_double.c +SRCS := test.c fx_s1516_double.c fx_s1516_longlong.c OBJS = $(SRCS:.c=.o) CC = gcc -CFLAGS = -c -Wall -g -# CFLAGS = -c -Wall -O2 +CFLAGS = -Wall -fx_x1516_double: $(OBJS) - $(CC) -o $@ $^ +fx_test: $(OBJS) + $(CC) -o $@ $^ -lm -.c.o: - $(CC) ${CFLAGS} $< +test.o: test.c + $(CC) $(CFLAGS) -c $^ -clean: - -rm $(OBJS) - rm fx_x1516_double +fx_s1516_double.o: fx_s1516_double.c + $(CC) -c $^ + +fx_s1516_longlong.o: fx_s1516_longlong.c + $(CC) -c $^ -dep: - $(CC) -M $(SRCS) \ No newline at end of file +clean: + rm $(OBJS) fx_test \ No newline at end of file diff --git a/README.md b/README.md index d402b0090d6e8d8748e7024fc666e5400c9380bb..0767b2b2966e9b2e674169b78be0684f5a43bf34 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ -## fx_s1516 Library +## fx_s1516 Library - Step 1(double) ### macros @@ -50,20 +50,20 @@ ### functions -| Name | Return type | Parameters | Description | -| ---------------- | ----------- | --------------------- | ------------------------------------------------- | -| double_to_fx | double | double a | double형 a값을 fx_s1516형으로 형 변환 | -| fx_to_double | double | fx_s1516 a | fx_s1516형 a값을 double형으로 형 변환 | -| fx_s1516_add | double | double a, double b | fx_s1516 연산으로 a + b값을 계산 | -| fx_s1516_sub | double | double a, double b | fx_s1516 연산으로 a - b값을 계산 | -| fx_s1516_mul | double | double a, double b | fx_s1516 연산으로 a * b값을 계산 | -| fx_s1516_div | double | double a, double b | fx_s1516 연산으로 a / b값을 계산 | -| degree_to_radian | double | fx_s1516 a | fx_s1516형 a값을 radian 값으로 변환 | -| fx_s1516_sin | double | double a | 라디안 값을 받아 fx_s1516 연산으로 sin값을 계산 | -| fx_s1516_sqrt | double | double a | fx_s1516 연산으로 a의 제곱근 계산 | -| fx_s1516_pow | double | double a, double b | fx_s1516 연산으로 a의 b거듭제곱을 계산 | -| fx_s1516_log | double | double a, double b | fx_s1516 연산으로 b를 밑으로 하는 a의 로그를 계산 | -| baselog | double | double a, double base | base를 밑으로 하는 a의 로그를 계산 | +| Name | Return type | Parameters | Description | +| -------------------- | ----------- | --------------------- | ------------------------------------------------- | +| double_to_fx | double | double a | double형 a값을 fx_s1516형으로 형 변환 | +| fx_to_double | double | fx_s1516 a | fx_s1516형 a값을 double형으로 형 변환 | +| fx_s1516_double_add | double | double a, double b | fx_s1516 연산으로 a + b값을 계산 | +| fx_s1516_double_sub | double | double a, double b | fx_s1516 연산으로 a - b값을 계산 | +| fx_s1516_double_mul | double | double a, double b | fx_s1516 연산으로 a * b값을 계산 | +| fx_s1516_double_div | double | double a, double b | fx_s1516 연산으로 a / b값을 계산 | +| degree_to_radian | double | fx_s1516 a | fx_s1516형 a값을 radian 값으로 변환 | +| fx_s1516_double_sin | double | double a | 라디안 값을 받아 fx_s1516 연산으로 sin값을 계산 | +| fx_s1516_double_sqrt | double | double a | fx_s1516 연산으로 a의 제곱근 계산 | +| fx_s1516_double_pow | double | double a, double b | fx_s1516 연산으로 a의 b거듭제곱을 계산 | +| fx_s1516_double_log | double | double a, double b | fx_s1516 연산으로 b를 밑으로 하는 a의 로그를 계산 | +| baselog | double | double a, double base | base를 밑으로 하는 a의 로그를 계산 | @@ -138,6 +138,158 @@ ### +## fx_s1516 Library - Step 2(long long) + +### macros + +| Macro | Description | +| ------ | ----------------------------------------------------- | +| P2_16 | 고정 소수점 표현을 위해 필요한 2^16을 정수형으로 정의 | +| fP2_16 | 고정 소수점 표현을 위해 필요한 2^16을 실수형으로 정의 | + +### functions + +| Name | Return type | Parameters | +| ---------------------- | ----------- | ---------------------- | +| longlong_to_fx | fx_s1516 | long long a | +| fx_to_longlong | long long | fx_s1516 a | +| fx_s1516_longlong_mul0 | fx_s1516 | fx_s1516 a, fx_s1516 b | +| fx_s1516_longlong_mul1 | fx_s1516 | fx_s1516 a, fx_s1516 b | +| fx_s1516_longlong_mul2 | fx_s1516 | fx_s1516 a, fx_s1516 b | +| fx_s1516_longlong_mul3 | fx_s1516 | fx_s1516 a, fx_s1516 b | +| fx_s1516_longlong_mul4 | fx_s1516 | fx_s1516 a, fx_s1516 b | +| fx_s1516_longlong_div0 | fx_s1516 | fx_s1516 a, fx_s1516 b | +| fx_s1516_longlong_div1 | fx_s1516 | fx_s1516 a, fx_s1516 b | +| fx_s1516_longlong_div2 | fx_s1516 | fx_s1516 a, fx_s1516 b | +| fx_s1516_longlong_sin | fx_s1516 | fx_s1516 fa | +| fx_s1516_longlong_sqrt | fx_s1516 | fx_s1516 fa | + +## Function Descriptions + +### 1. Type conversion + +- **longlong_to_fx** + long long 형 변수를 fx_s1516형으로 형 변환 +- **fx_to_longlong** + fx_s1516형 변수를 long long 형으로 형 변환 + +### 2. Multiplication + +- **fx_s1516_longlong_mul0** + - 두 수 a, b를 받아 a를 fixed64(long long)으로 형 변환 한 후 b와 곱하여 16 만큼 오른쪽으로 shift하여 연산한다. +- **fx_s1516_longlong_mul1** + - 두 수 a, b를 받아 먼저 a와 b를 곱한 뒤 소수부의 크기 즉, 16 만큼 오른쪽으로 shift 연산한다. a, b가 큰 수일 경우 overflow가 발생할 수 있다. +- **fx_s1516_longlong_mul2** + - 두 수 a, b를 받아 a와 b 각각 오른쪽으로 8 만큼 shift연산한 뒤 곱한다. + - mul1과 달리 overflow의 위험은 줄지만 작은 수의 경우에는 shift 연산에 의해 underflow가 발생활 확률이 있으므로 정확도가 낮아진다. +- **fx_s1516_longlong_mul3** + - 두 수 a, b를 받아 a는 10만큼, b는 6 만큼 오른쪽으로 shift연산한 뒤 곱한다. + - mul2와 비슷하지만 a를 더 많이 shift하므로 a에서 underflow가 발생할 확률이 높고 비교적 정확도가 떨어진다. + - a와 b중 큰 수가 왼쪽에 있을 때 그 반대보다 더 정확한 연산을 한다. +- **fx_s1516_longlong_mul4** + - 두 수 a, b를 받아 a와 b 각각 오른쪽으로 4 만큼 shift연산하여 곱한 후 다시 오른쪽으로 8만큼 shift연산한다. + - a와 b를 그대로 곱하지 않고 4비트씩 shift하여 overflow 확률을 낮추면서 4 비트씩 밖에 shift하지 않으므로 underflow가 발생할 확률도 낮은 방법이다. + +### 3. Division + +- **fx_s1516_longlong_div0** + - 두 수 중에서 나누어 지는 수 a를 fixed64(long long)으로 캐스팅 한 후 소수부 크기 16만큼 왼쪽으로 shift 연산을 하고난 후 나누는 수 b로 나누어 연산한다. + - a, b가 비슷한 범위의 숫자이거나 실수형 계산 시 소수점이 나오는 경우 오차범위가 커지므로 그것을 방지하는 방법이다. + - 캐스팅 작업이 있어 다른 함수보다 비교적 속도가 느리다. +- **fx_s1516_longlong_div1** + - div0과 다르게 별도의 캐스팅 없이 나누어지는 수 a를 8비트 왼쪽으로 shift한 후 나누는 수 b로 나누어 다시 왼쪽으로 8비트 shift 하여 연산한다. + - 캐스팅 작업이 없으므로 속도가 비교적 빠르며 a가 큰 수일 경우 overflow의 가능성이 있다. +- **fx_s1516_longlong_div2** + - 앞의 두 함수와 다르게 나누는 수 b를 오른쪽으로 16비트 shift한 후 나누어지는 수 a를 나누어 연산한다. + - div1과 마찬가지로 캐스팅이 없어서 비교적 연산 속도가 빠르며 overflow 발생 확률은 작지만 b가 작은 수일 경우 underflow가 발생할 수 있다. + +### 4. Exponent + +- **fx_s1516_longlong_sin** + + - Sin Table + + ```bash + const fixed32 fx32_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 + }; + ``` + + - 0 ~ 91도 까지의 sin 값을 저장하는 table이며 math 등 외부 라이브러리의 잦은 호출을 방지하여 성능상 이점을 준다. + + - 제일 먼저, 입력으로 받은 라디안 값 fa가 음수인지를 체크하여 만약 음수라면 부호를 -로 바꾸어 주고 계산을 위해 fa를 양수로 바꾼다. 이후 fa가 360보다 클 수도 있으므로 fa를 360으로 나눈 후 계산을 진행한다. + + - sin함수는 180 ~ 360 사이에서는 음수이기 때문에 fa를 미리 define해 둔 FX32_180과 비교하여 그것보다 크거나 같다면 부호를 반전하고 fa에서 그 값을 빼준다. + + - 이후 미리 구해둔 sin table을 이용하여 ret0과 diff를 구한 후 shift연산하여 sin 값을 계산한다. + +## Functions Accuracy Comparison + +### 1. Multiplication + +``` +fx_s1516_double_mul: 22888.183594 +fx_s1516_longlong_mul0: 22888 +fx_s1516_longlong_mul1: 22888 +fx_s1516_longlong_mul2: 22815 +fx_s1516_longlong_mul3: 22649 +fx_s1516_longlong_mul4: 22888 +``` + +- mul0, mul1, mul4는 높은 정확도를 보이는 것으로 보아 overflow가 발생하지 않았고, mul4에서는 shift로 인한 비트 손실이 발생하지 않았음을 알 수 있다. +- mul2, mul3은 다른 함수에 비해 비교적 낮은 정확도를 보였는데 많은 수의 비트를 shift하다 보니 비트 손실이 발생하여 정확도가 낮아졌음을 예측해 볼 수 있다. + +### 2. Division + +``` +fx_s1516_double_div: 131072.000000 +fx_s1516_longlong_div0: 131072 +fx_s1516_longlong_div1: 131072 +fx_s1516_longlong_div2: 142857 +``` + +- div0, div1은 높은 정확도를 보이며 shift로 인해 a의 값이 손실되지 않았음을 알 수 있다. +- div2는 비교적 낮은 정확도를 보이는데 b를 shift하며 어느 정도의 데이터가 손실되었음을 예측해 볼 수 있다. + + + +## Functions Speed Comparison + +### 1. Multiplication + + + +- time이 적을수록 빠른 함수이므로 mul2 > mul1 > mul3 > mul0 > mul4 순서로 속도가 빠른 것을 알 수 있다. +- shift 연산 3번, 곱셈 연산 1번을 실행하는 mul4가 가장 느렸고, fixed64로 캐스팅하는 작업이 있는 mul0도 비교적 느린 것을 확인할 수 있었다. +- 나머지 mul2, mul1, mul3 세 연산은 속도가 같거나 거의 차이가 없는 것을 확인할 수 있다. +- 위 결과로 미루어 보아 캐스팅, shift 연산의 횟수 등이 실행 속도에 영향을 주는 것으로 예상해볼 수 있다. + +### 2. Division + + + +- div 연산은 div2 > div1 > div0 순서로 속도가 빠른 것을 확인할 수 있다. +- mul에서 확인한 것과 같이 캐스팅 연산이 있는 div0이 상대적으로 느렸으며 shift 횟수가 1회 더 많은 div1이 div2보다 느린 것을 확인할 수 있다. +- div의 결과로도 캐스팅, shift 연산의 횟수가 실행 속도에 영향을 주는 것으로 예상이 가능하다. + + + +## Test method + +### Test file change + +- ```ifdef``` 구문을 사용해 매크로에 따라 실행되는 구문이 다르게 수정하였다. +- 매크로 종류 + - fx_mul: double, long long 곱셈 함수 테스트 + - fx_div: double, long long 나눗셈 함수 테스트 + - fx_sin: double, long long sin 함수 테스트 + - fx_sqrt: double, long long 제곱근 함수 테스트 + +### Run make + +- make 사용시 테스트 하고 싶은 함수의 종류에 따라 다른 매크로를 정의하여 실행 파일을 만든 후 해당 실행파일을 실행한다. + - ```make CFLAGS=-D[MACRO]``` + - ```./fx_test.exe``` + ## References ###### Randy Yates, Fixed-Point Arithmetic: An Introudction. pp6-pp11 diff --git a/fx_s1516.zip b/fx_s1516.zip deleted file mode 100644 index 70ef6a774dcd41ddffca313134466ff6361c5187..0000000000000000000000000000000000000000 Binary files a/fx_s1516.zip and /dev/null differ diff --git a/fx_s1516_double.c b/fx_s1516_double.c index 1acdb27a4215b367d29cbd5e3f2d617650fb7744..71584b1e43af390ca35c83a8ab08ec90affb00a2 100644 --- a/fx_s1516_double.c +++ b/fx_s1516_double.c @@ -1,47 +1,47 @@ // fx_s1516_double.c file #include "fx_s1516_double.h" -double double_to_fx(double a) { - return ((a) * P2_16); +fx_s1516 double_to_fx(double a) { + return (int)(((a) * P2_16)); } double fx_to_double(fx_s1516 a) { return ((double)(a) / P2_16); } -double fx_s1516_add(double a, double b){ +double fx_s1516_double_add(double a, double b){ return double_to_fx((a) + (b)); } -double fx_s1516_sub(double a, double b){ +double fx_s1516_double_sub(double a, double b){ return double_to_fx((a) - (b)); } -double fx_s1516_mul(double a, double b) { +double fx_s1516_double_mul(double a, double b) { return double_to_fx((a) * (b) * P2_16); } -double fx_s1516_div(double a, double b) { +double fx_s1516_double_div(double a, double b) { return double_to_fx((a) / (b) / P2_16); } -double degree_to_radian(fx_s1516 a) { - return ((a) * M_PI / 180); +double degree_to_radian(double a) { + return ((a) * fx_s1516_PI / 180); } -double fx_s1516_sin(double a) { +double fx_s1516_double_sin(double a) { return double_to_fx(sin(a * P2_16) / (P2_16)); } -double fx_s1516_sqrt(double a) { +double fx_s1516_double_sqrt(double a) { return double_to_fx(sqrt(a) / sqrt(P2_16)); } -double fx_s1516_pow(double a, double b) { +double fx_s1516_double_pow(double a, double b) { return double_to_fx(pow(a, (double)b) * pow(P2_16, (double)b - 1)); } -double fx_s1516_log(double a, double b) { +double fx_s1516_double_log(double a, double b) { return double_to_fx(baselog(a * P2_16, b) / (P2_16)); } diff --git a/fx_s1516_double.h b/fx_s1516_double.h index b65a88560c6ab11e9bc18ed18dca8af2bdeeddf8..ecd0b36f05180bb0989d34c9ac2d6d75a5fd013d 100644 --- a/fx_s1516_double.h +++ b/fx_s1516_double.h @@ -1,26 +1,25 @@ -#pragma once #define __FX_S1516_DOUBLE_H typedef int fx_s1516; -#include <stdio.h> #define _USE_MATH_DEFINES #include <math.h> -#define P2_16 65536.0f +#include <stdio.h> +#define P2_16 65536 +#define fP2_16 65536.0 #define e M_E #define fx_s1516_PI M_PI #define fx_s1516_INVERSE_PI 1/M_PI - -extern double double_to_fx(double a); -extern double baselog(double a, double base); -extern double fx_s1516_add(double a, double b); -extern double fx_s1516_sub(double a, double b); -extern double fx_s1516_mul(double a, double b); -extern double fx_s1516_div(double a, double b); -extern double fx_s1516_sqrt(double a); -extern double fx_s1516_pow(double a, double b); -extern double fx_s1516_log(double a, double b); -extern double degree_to_radian(fx_s1516 a); +extern fx_s1516 double_to_fx(double a); extern double fx_to_double(fx_s1516 a); -extern double fx_s1516_sin(double a); \ No newline at end of file +extern double baselog(double a, double base); +extern double fx_s1516_double_add(double a, double b); +extern double fx_s1516_double_sub(double a, double b); +extern double fx_s1516_double_mul(double a, double b); +extern double fx_s1516_double_div(double a, double b); +extern double fx_s1516_double_sqrt(double a); +extern double fx_s1516_double_pow(double a, double b); +extern double fx_s1516_double_log(double a, double b); +extern double degree_to_radian(double a); +extern double fx_s1516_double_sin(double a); diff --git a/gprof/fx_s1516_longlong.c b/fx_s1516_longlong.c similarity index 89% rename from gprof/fx_s1516_longlong.c rename to fx_s1516_longlong.c index cb8813e4c76a2ef3c1cedd19c0ff61e33e43cad2..8d59263c3e0f347e0a3ce4947ff5ab98de3847f2 100644 --- a/gprof/fx_s1516_longlong.c +++ b/fx_s1516_longlong.c @@ -62,7 +62,7 @@ int sqrt_lut[1025] = fx_s1516 longlong_to_fx(long long a) { - return (a * 65536); + return (int)(((a) * fP2_16)); } long long fx_to_longlong(fx_s1516 a) @@ -72,7 +72,7 @@ long long fx_to_longlong(fx_s1516 a) fx_s1516 fx_s1516_longlong_mul0(fx_s1516 a, fx_s1516 b) { - return (fixed32)(((fixed64)a * b) >> 16); + return (fx_s1516)(((fixed64)a * b) >> 16); } fx_s1516 fx_s1516_longlong_mul1(fx_s1516 a, fx_s1516 b) @@ -95,33 +95,36 @@ fx_s1516 fx_s1516_longlong_mul4(fx_s1516 a, fx_s1516 b) return (fixed32)((a >> 4) * (b >> 4) >> 8); } -//mul���� (fixed) conversion ���ϸ� : ���ڰ� -1 ���� 1�� (�۰�)����ȭ �Ǿ������� ������ ������. -// fixed�� �ٿ��� ���� �غ��� -// ����Ʈ ���굵 �������� -// for ���� ���� �������� -// ���� ���� ���� �ź��� ���� ū�ű��� �� �־�� +// mul에서 (fixed) conversion 안하면 : 숫자가 -1 부터 1로 (작게)정규화 되어있으면 곱셈이 빠르다. +// fixed도 붙였다 땠다 해보고 +// 시프트 연산도 나눠보고 +// for 문도 많이 돌려보고 +// 값도 아주 작은 거부터 아주 큰거까지 다 넣어보고 -// ������ ���� : shift �������� ������ ���� 0�� �Ǿ� ������ �� �����Ƿ� �����ؾ� �Ѵ�. +// 나눗셈 연산 : shift 과정에서 나누는 수가 0이 되어 나눠질 수 있으므로 조심해야 한다. fx_s1516 fx_s1516_longlong_div0(fx_s1516 a, fx_s1516 b) { return (fixed32)(((fixed64)a << 16) / b); } -/* -* a(�������� ��)�� long long���� ij����, 16bit shift ���� �� b(������ ��)�� ���� -* long long ij����: int(32bit)�� a�� long long(64bit)�� ij���������ν� �ӵ��� ���������� 16bit shift ������ �� �� �������� �ս��� ���� �� �ִ�. -* fx_s1516_longlong�� ������ ��Ģ�����̹Ƿ� a�� b�� ����� ������ �����̰ų� �Ǽ������� ������� �� �Ҽ����� ������ �������� ��� ���������� Ŀ���� ������ �̰��� �����ϰ��� �̸� a�� 16bit shift ��Ų �� b�� ������. +/* <div0> +* a(나눠지는 수)를 long long으로 캐스팅, 16bit shift 연산 후 b(나누는 수)로 나눔 +* long long 캐스팅: int(32bit)인 a를 long long(64bit)로 캐스팅함으로써 속도가 느려지지만 +* 16bit shift 연산을 할 때 데이터의 손실을 줄일 수 있다. +* fx_s1516_longlong은 정수형 사칙연산이므로 a와 b가 비슷한 범위의 숫자이거나 +* 실수형으로 계산했을 때 소수점이 나오는 나눗셈인 경우 오차범위가 커지기 때문에 +* 이것을 방지하고자 미리 a를 16bit shift 시킨 후 b로 나눴다. */ fx_s1516 fx_s1516_longlong_div1(fx_s1516 a, fx_s1516 b) { - return (fixed32)(((a << 8) / b) << 8); // ������ �ս�, ū ���ڿ� ���ؼ��� ������ ŭ + return (fixed32)(((a << 8) / b) << 8); // ������ �ս�, ū ���ڿ� ���ؼ��� ������ ŭ } /* -* long long���� ij�������� �ʰ� int������ ������� ������ ���� �ӵ��� ������. -* ū ���� ��� �������� �ս��� ���� �� �ִ�. -* Overflow ���ɼ��� �۾�����. +* long long으로 캐스팅하지 않고 int형으로 나눠줬기 때문에 연산 속도가 빠르다. +* 큰 수일 경우 데이터의 손실이 있을 수 있다. +* Overflow 가능성은 작아진다. */ fx_s1516 fx_s1516_longlong_div2(fx_s1516 a, fx_s1516 b) @@ -130,9 +133,9 @@ fx_s1516 fx_s1516_longlong_div2(fx_s1516 a, fx_s1516 b) } /* -* div1�� ���� long long���� ij�������� �ʾұ� ������ ���� �ӵ��� ������. -* Overflow�� ��Ȯ���� ����. -* b(������ ��)�� ���� ���� ��� �������� �ս��� ũ��. +* div1과 같이 long long으로 캐스팅하지 않았기 때문에 연산 속도가 빠르다. +* Overflow 발생확률이 높다. +* b(나누는 수)가 작은 수일 경우 데이터의 손실이 크다. */ fx_s1516 fx_s1516_longlong_sin(fx_s1516 fa) diff --git a/gprof/fx_s1516_longlong.h b/fx_s1516_longlong.h similarity index 91% rename from gprof/fx_s1516_longlong.h rename to fx_s1516_longlong.h index eb2f2bf28bc986e0661c7703d401b97c784c3d9f..c07d910f21622b1b67c231b1d60bfe7b2d2f5db2 100644 --- a/gprof/fx_s1516_longlong.h +++ b/fx_s1516_longlong.h @@ -1,8 +1,11 @@ //fx_1516_longlong.h file -#pragma once +#define __FX_S1516_LONGLONG_H #include <stdio.h> +#define P2_16 65536 +#define fP2_16 65536.0 + typedef int fx_s1516; typedef long fixed32; typedef long long fixed64; diff --git a/fx_s1516_longlong/fx_s1516_longlong.c b/fx_s1516_longlong/fx_s1516_longlong.c deleted file mode 100644 index c8069f20b8f1e9aa861f977dcf36480ec4ba72bf..0000000000000000000000000000000000000000 --- a/fx_s1516_longlong/fx_s1516_longlong.c +++ /dev/null @@ -1,37 +0,0 @@ -//fx_1516_longlong.c file -#include "fx_s1516_longlong.h" -#define FX32_90 0x005A0000 -#define FX32_180 0x00B40000 -#define FX32_360 0x01680000 - -// sin table -const fixed32 fx32_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 - }; - -fx_s1516_sin(fixed32 fa){ - int sign = 1; - fixed32 ret0, diff; - int idx; - if ( fa < 0 ) - { - sign = -1; - fa *= -1; - } - fa = fa % FX32_360; - if ( fa >= FX32_180 ) - { - sign *= -1; - fa -= FX32_180; - } - if ( fa > FX32_90 ) - fa = FX32_180 - fa; - idx = fa>>16; - ret0 = fx32_SinTable[idx]; - diff = fx32_SinTable[idx+1]-ret0; - return ( sign *( ret0 + ((diff*(fa&0xFFFF))>>16) )); -} \ No newline at end of file diff --git a/fx_s1516_longlong/fx_s1516_longlong.h b/fx_s1516_longlong/fx_s1516_longlong.h deleted file mode 100644 index af4313e3010bcbf5ebd7584bea2cf1e0c97ab36a..0000000000000000000000000000000000000000 --- a/fx_s1516_longlong/fx_s1516_longlong.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -typedef long fixed32; -typedef long long fixed64; - -#define mul0(a, b) (fixed32) ((fixed64)(a) * (b) >> 16) -#define mul1(a, b) (fixed32) ((a) * (b) >> 16) // no fixed -#define mul2(a, b) (fixed32) ((a>>8) * (b>>8)) -#define mul3(a, b) (fixed32) ((a>>10) * (b>>6)) -#define mul4(a, b) (fixed32) ((a>>4) * (b>>4) >> 8) - -// mul에서 (fixed) conversion 안하면 : 숫자가 -1 부터 1로 (작게)정규화 되어있으면 곱셈이 빠르다. -// fixed도 붙였다 땠다 해보고 -// 시프트 연산도 나눠보고 -// for 문도 많이 돌려보고 -// 값도 아주 작은 거부터 아주 큰거까지 다 넣어보고 - -#define div0(a, b) (fixed32)(((fixed64)(a) << 16) / (b)) -#define div1(a, b) ((((a) << 8) / (b)) << 8) -#define div2(a, b) ((a) / ((b) >> 16)) - -// 나눗셈 연산 : shift 과정에서 나누는 수가 0이 되어 나눠질 수 있으므로 조심해야 한다. - -/* <div0> -* a(나눠지는 수)를 long long으로 캐스팅, 16bit shift 연산 후 b(나누는 수)로 나눔 -* long long 캐스팅: int(32bit)인 a를 long long(64bit)로 캐스팅함으로써 속도가 느려지지만 16bit shift 연산을 할 때 데이터의 손실을 줄일 수 있다. -* fx_s1516_longlong은 정수형 사칙연산이므로 a와 b가 비슷한 범위의 숫자이거나 실수형으로 계산했을 때 소수점이 나오는 나눗셈인 경우 오차범위가 커지기 때문에 이것을 방지하고자 미리 a를 16bit shift 시킨 후 b로 나눴다. - - <div1> -* long long으로 캐스팅하지 않고 int형으로 나눠줬기 때문에 연산 속도가 빠르다. -* 큰 수일 경우 데이터의 손실이 있을 수 있다. -* Overflow 가능성은 작아진다. - - <div2> -* div1과 같이 long long으로 캐스팅하지 않았기 때문에 연산 속도가 빠르다. -* Overflow 발생확률이 높다. -* b(나누는 수)가 작은 수일 경우 데이터의 손실이 크다. -*/ \ No newline at end of file diff --git a/gprof/fx_s1516_double.c b/gprof/fx_s1516_double.c deleted file mode 100644 index 4ebe7a99b68dcaa876cbc2dace16fbe0a8a97e7e..0000000000000000000000000000000000000000 --- a/gprof/fx_s1516_double.c +++ /dev/null @@ -1,51 +0,0 @@ -// fx_s1516_double.c file -#include "fx_s1516_double.h" - -double double_to_fx(double a) { - return ((a) * P2_16); -} - -double fx_to_double(fx_s1516 a) { - return ((double)(a) / P2_16); -} - -double fx_s1516_double_add(double a, double b){ - return double_to_fx((a) + (b)); -} - -double fx_s1516_double_sub(double a, double b){ - return double_to_fx((a) - (b)); -} - -double fx_s1516_double_mul(double a, double b) { - return double_to_fx((a) * (b) * P2_16); -} - -double fx_s1516_double_div(double a, double b) { - return double_to_fx((a) / (b) / P2_16); -} - -double degree_to_radian(double a) { - return ((a) * fx_s1516_PI / 180); -} - -double fx_s1516_double_sin(double a) { - return double_to_fx(sin(a * P2_16) / (P2_16)); -} - -double fx_s1516_double_sqrt(double a) { - return double_to_fx(sqrt(a) / sqrt(P2_16)); -} - -double fx_s1516_double_pow(double a, double b) { - return double_to_fx(pow(a, (double)b) * pow(P2_16, (double)b - 1)); -} - -double fx_s1516_double_log(double a, double b) { - return double_to_fx(baselog(a * P2_16, b) / (P2_16)); -} - -double baselog(double a, double base) -{ - return log(a) / log(base); -} \ No newline at end of file diff --git a/gprof/fx_s1516_double.h b/gprof/fx_s1516_double.h deleted file mode 100644 index 7dc96719004c92cca2783fb8b7befa583921a88f..0000000000000000000000000000000000000000 --- a/gprof/fx_s1516_double.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#define __FX_S1516_DOUBLE_H - -typedef int fx_s1516; - -#define _USE_MATH_DEFINES -#include <math.h> -#include <stdio.h> -#define P2_16 65536 -#define fP2_16 65536.0 -#define e M_E -#define fx_s1516_PI M_PI -#define fx_s1516_INVERSE_PI 1/M_PI - -extern double double_to_fx(double a); -extern double fx_to_double(fx_s1516 a); -extern double baselog(double a, double base); -extern double fx_s1516_double_add(double a, double b); -extern double fx_s1516_double_sub(double a, double b); -extern double fx_s1516_double_mul(double a, double b); -extern double fx_s1516_double_div(double a, double b); -extern double fx_s1516_double_sqrt(double a); -extern double fx_s1516_double_pow(double a, double b); -extern double fx_s1516_double_log(double a, double b); -extern double degree_to_radian(double a); -extern double fx_s1516_double_sin(double a); diff --git a/images/image-20200819214427030.png b/images/image-20200819214427030.png new file mode 100644 index 0000000000000000000000000000000000000000..452eada3fa2954e6d6594c1ab9d74ede3bdae52f Binary files /dev/null and b/images/image-20200819214427030.png differ diff --git a/images/image-20200819214731886.png b/images/image-20200819214731886.png new file mode 100644 index 0000000000000000000000000000000000000000..0744c710e2c64866534819d644f595b1ce0dfd69 Binary files /dev/null and b/images/image-20200819214731886.png differ diff --git a/images/image-20200819214809542.png b/images/image-20200819214809542.png new file mode 100644 index 0000000000000000000000000000000000000000..34215be3e01a1f6059a27f82839d05e946e2e6c8 Binary files /dev/null and b/images/image-20200819214809542.png differ diff --git a/images/image-20200819214821430.png b/images/image-20200819214821430.png new file mode 100644 index 0000000000000000000000000000000000000000..08ec9843ad4a990f261fcea165cf961d911d327e Binary files /dev/null and b/images/image-20200819214821430.png differ diff --git a/longtest.c b/longtest.c index 01b019aac0e93eec221e4282edc5faab95ee147c..c237d946e2d4cf70ed804f17e64dabe622291f42 100644 --- a/longtest.c +++ b/longtest.c @@ -1,15 +1,17 @@ #include "fx_s1516_longlong.h" -#include <stdio.h> int main() { long long a = 3000000; long long b = 5000000; - printf("mul0 : %d\n", mul1(a, b)); - printf("mul1 : %d\n", mul1(a, b)); - printf("mul2 : %d\n", mul2(a, b)); - printf("mul3 : %d\n", mul3(a, b)); - printf("mul4 : %d\n", mul4(a, b)); + fx_s1516 fa = longlong_to_fx(a); + fx_s1516 fb = longlong_to_fx(b); + + printf("exact value: %lld, mul0 : %d, error: %lld\n", (a * b), fx_s1516_longlong_mul0(fa, fb), (a * b) - fx_to_longlong(fx_s1516_longlong_mul0(fa, fb))); + printf("mul1 : %d\n", fx_s1516_longlong_mul1(a, b)); + printf("mul2 : %d\n", fx_s1516_longlong_mul2(a, b)); + printf("mul3 : %d\n", fx_s1516_longlong_mul3(a, b)); + printf("mul4 : %d\n", fx_s1516_longlong_mul4(a, b)); } \ No newline at end of file diff --git a/test.c b/test.c index 54f23b364a5ba16b12a2f41785673c49cf790bf0..6f4798cfc5608c58afe937fc4b61d39070a52f20 100644 --- a/test.c +++ b/test.c @@ -1,33 +1,118 @@ -#include "fx_s1516_double.h" - -#define fx_mul(a, b) ((a)*(b)) - -/* -Make first prototype fx_sXXYY_double.c with double and math.h -define macro fx_sXXYY_double.h program test.c -*/ +#include "fx_s1516_double.h" +#include "fx_s1516_longlong.h" int main() { - fx_s1516 a = 131072; - fx_s1516 b = 65536; - - double fa = fx_to_double(a); - double fb = fx_to_double(b); - - printf("a : %d b : %d\nfa : %lf fb : %lf\noriginal a : %lf original b : %lf\n\n", a, b, fa, fb, double_to_fx(fa), double_to_fx(fb)); - - printf("Add : %-15d %lf\n", a + b, fx_s1516_add(fa, fb)); - printf("Sub : %-15d %lf\n", a - b, fx_s1516_sub(fa, fb)); - printf("Mul : %-15lld %lf\n", (long long)a * b, fx_s1516_mul(fa, fb)); - printf("Div : %-15lf %lf\n\n", (double)a / b, fx_s1516_div(fa, fb)); - - printf("Sin : %-15lf %lf\n", sin(degree_to_radian(a)), fx_s1516_sin(degree_to_radian(fa))); - printf("Sqrt : %-15lf %lf\n", sqrt(a), fx_s1516_sqrt(fa)); - printf("Sqrt : %-15lf %lf\n", sqrt(b), fx_s1516_sqrt(fb)); - printf("Pow : %-15lld %lf\n", (long long)pow(a, 2), fx_s1516_pow(fa, 2)); - printf("Log : %-15lf %lf\n\n", baselog(a, e), fx_s1516_log(fa, e)); - - printf("PI : %f\n", fx_s1516_PI); - printf("INVERSE PI : %f\n", fx_s1516_INVERSE_PI); + double sum = 0; + int i; + +#ifdef fx_mul + fx_s1516 a = 30000; + fx_s1516 b = 50000; + + double fa = fx_to_double(a); + double fb = fx_to_double(b); + + printf("fx_s1516_double_mul: %lf\n", fx_s1516_double_mul(fa, fb) / P2_16); + printf("fx_s1516_longlong_mul0: %d\n", fx_s1516_longlong_mul0(a, b)); + printf("fx_s1516_longlong_mul1: %d\n", fx_s1516_longlong_mul1(a, b)); + printf("fx_s1516_longlong_mul2: %d\n", fx_s1516_longlong_mul2(a, b)); + printf("fx_s1516_longlong_mul3: %d\n", fx_s1516_longlong_mul3(a, b)); + printf("fx_s1516_longlong_mul4: %d\n", fx_s1516_longlong_mul4(a, b)); + + for (i = 0; i < 10000000; i++) + { + sum += fx_s1516_double_mul(fa, fb); + } + for (i = 0; i < 10000000; i++) + { + sum += fx_s1516_longlong_mul0(a, b); + } + for (i = 0; i < 10000000; i++) + { + sum += fx_s1516_longlong_mul1(a, b); + } + for (i = 0; i < 10000000; i++) + { + sum += fx_s1516_longlong_mul2(a, b); + } + for (i = 0; i < 10000000; i++) + { + sum += fx_s1516_longlong_mul3(a, b); + } + for (i = 0; i < 10000000; i++) + { + sum += fx_s1516_longlong_mul4(a, b); + } +#endif + +#ifdef fx_div + fx_s1516 a = 1000000; + fx_s1516 b = 500000; + + double fa = fx_to_double(a); + double fb = fx_to_double(b); + + printf("fx_s1516_double_div: %lf\n", fx_s1516_double_div(fa, fb) * P2_16); + printf("fx_s1516_longlong_div0: %d\n", fx_s1516_longlong_div0(a, b)); + printf("fx_s1516_longlong_div1: %d\n", fx_s1516_longlong_div1(a, b)); + printf("fx_s1516_longlong_div2: %d\n", fx_s1516_longlong_div2(a, b)); + + for (i = 0; i < 10000000; i++) + { + sum += fx_s1516_double_div(fa, fb); + } + for (i = 0; i < 10000000; i++) + { + sum += fx_s1516_longlong_div0(a, b); + } + for (i = 0; i < 10000000; i++) + { + sum += fx_s1516_longlong_div1(a, b); + } + for (i = 0; i < 10000000; i++) + { + sum += fx_s1516_longlong_div2(a, b); + } +#endif + +#ifdef fx_sin + fx_s1516 a = 30; + + double fa = fx_to_double(a); + + printf("fx_s1516_double_sin: %lf\n", fx_s1516_double_sin(degree_to_radian(fa))); + printf("fx_s1516_longlong_sin: %lf\n", fx_s1516_longlong_sin(a * P2_16) / fP2_16); + + for (i = 0; i < 10000000; i++) + { + sum += fx_s1516_double_sin(degree_to_radian(fa)); + } + for (i = 0; i < 10000000; i++) + { + sum += (fx_s1516_longlong_sin(a * P2_16) / fP2_16); + } +#endif + +#ifdef fx_sqrt + fx_s1516 a = 123; + + double fa = fx_to_double(a); + + printf("fx_s1516_double_sqrt: %lf\n", fx_s1516_double_sqrt(fa)); + printf("fx_s1516_longlong_sqrt: %lf\n", fx_s1516_longlong_sqrt(a) / 256.0); + + for (i = 0; i < 10000000; i++) + { + sum += fx_s1516_double_sqrt(fa); + } + for (i = 0; i < 10000000; i++) + { + sum += (fx_s1516_longlong_sqrt(a) / 256.0); + } +#endif + + printf("sum: %lf", sum); + + return 0; }