在学习CORDIC(Coordinate Rotation Digital Computer)算法的时候,最主要的疑问是:浮点数怎么做移位运算?如果CORDIC算法中不使用移位运算,而是直接使用浮点数乘法(除以浮点常数的除法会被C++编译器优化为乘法),那么CORDIC算法的浮点乘法次数大大超过同精度的泰勒级数,完全失去了加快计算速度的意义。本文的代码使用整型变量实现CORDIC算法中的移位运算,并与浮点数实现的泰勒级数算法进行速度与精度的对比。在电脑和Arduino nano上进行了测试:两个不同平台上,泰勒级数的速度均大大超过了CORDIC算法。在电脑CPU上,泰勒级数的速度与标准库接近。在Arduino nano上,泰勒级数的速度只有标准库的一半。
因为电脑CPU都有专门的浮点运算单元(FPU),所以浮点乘法相较于移位运算,耗时并没有长太多。Arduino nano是没有FPU的,按理说浮点乘法速度很慢(参见 https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html),CORDIC算法应该比泰勒级数快,但测试结果恰好相反,可能是因为我写得cordic函数用了
int n = (int)(Q * d2_pi);
Q -= n * pi_2;
return cosSign * x * scale;
return sinSign * y * scale;
这些浮点运算。
注意,在电脑上的代码中,数组angles的类型是浮点数,在Arduino nano上,angles(x1e8)的类型是32bit的整数,就是对应的浮点数乘上10^8再取整。这样做比使用浮点型的angles要快得多。
#include <stdio.h>
#include <cstdint>
#include <math.h>
#include <time.h>
#include <bitset>
#include <immintrin.h>
//#define SINGLE_PRECISION
#define FMADD
// K=1/(sqrt(1+1)*sqrt(1+1/4)*sqrt(1+1/16)*sqrt(1+1/64)...) 是一个无穷乘积
// K=0.6072529350088812561694467525049282631124...
// 在单精度情形,先将K * 10^9化成整数(要确保不超过2^32 =4294967296),
// 再进行加减法和移位运算,最后乘上1e-9化为浮点数。双精度情形类似。
#ifdef SINGLE_PRECISION
typedef float real;
typedef int32_t integer;
constexpr int32_t K = 607252935;
// 2^32 =4294967296
constexpr float scale = 1e-9;
constexpr uint8_t numIter = 32; //设得更大就会出错
constexpr float pi_2 = 1.570796326794897; // pi/2
constexpr float d2_pi = 0.6366197723675814; // 2/pi
constexpr float pi_128 = 0.02454369260617026; // pi/128
constexpr float d128_pi = 40.74366543152521; // 128/pi
#else
typedef double real;
typedef int64_t integer;
constexpr int64_t K = 607252935008881256;
// 2^64 =18446744073709551616
constexpr double scale = 1e-18;
constexpr uint8_t numIter = 40;
constexpr double pi_2 = 1.570796326794897; // pi/2
constexpr double d2_pi = 0.6366197723675814; // 2/pi
constexpr double pi_128 = 0.02454369260617026; // pi/128
constexpr double d128_pi = 40.74366543152521; // 128/pi
#endif
// 如果constexpr int64_t K = 6072529350088812561;
// 2^64 =18446744073709551616
// 2^63 = 9223372036854775808
// constexpr double scale = 1e-19;
//
// 则Q=1.5时,迭代中会出现x,y超过2^63的情况,导致溢出
// 把int64_t改为uint64_t也不行,Q=1.5时,会出现小数减大数的情况,导致错误。
struct {
const char cosine = 0;
const char sine = 1;
}triangle;
// atan(1), atan(1/2), atan(1/4), atan(1/8), atan(1/16), atan(1/32), atan(1/64), ...
constexpr real angles[41] = {
0.785398163397448, 0.463647609000806, 0.244978663126864, 0.124354994546761,
0.062418809995957, 0.031239833430268, 0.015623728620477, 0.007812341060101,
0.003906230131967, 0.001953122516479, 0.000976562189559, 0.000488281211195,
0.000244140620149, 0.000122070311894, 0.000061035156174, 0.000030517578116,
0.000015258789061, 0.000007629394531, 0.000003814697266, 0.000001907348633,
0.000000953674316, 0.000000476837158, 0.000000238418579, 0.000000119209290,
0.000000059604645, 0.000000029802322, 0.000000014901161, 0.000000007450581,
0.000000003725290, 0.000000001862645, 0.000000000931323, 0.000000000465661,
0.000000000232831, 0.000000000116415, 0.000000000058208, 0.000000000029104,
0.000000000014552, 0.000000000007276, 0.000000000003638, 0.000000000001819,
0.000000000000909 };
// cos(0),cos(pi/128),cos(2*pi/128),...,cos(63*pi/128),cos(pi/2)
constexpr real cosTable[65] = {
1.0,
0.9996988186962042, 0.9987954562051724, 0.9972904566786902, 0.9951847266721969,
0.9924795345987100, 0.9891765099647810, 0.9852776423889412, 0.9807852804032304,
0.9757021300385286, 0.9700312531945440, 0.9637760657954398, 0.9569403357322088,
0.9495281805930367, 0.9415440651830208, 0.9329927988347390, 0.9238795325112867,
0.9142097557035307, 0.9039892931234433, 0.8932243011955153, 0.8819212643483550,
0.8700869911087115, 0.8577286100002721, 0.8448535652497071, 0.8314696123025452,
0.8175848131515837, 0.8032075314806449, 0.7883464276266063, 0.7730104533627370,
0.7572088465064846, 0.7409511253549592, 0.7242470829514670, 0.7071067811865476,
0.6895405447370669, 0.6715589548470184, 0.6531728429537769, 0.6343932841636455,
0.6152315905806268, 0.5956993044924335, 0.5758081914178453, 0.5555702330196023,
0.5349976198870973, 0.5141027441932217, 0.4928981922297841, 0.4713967368259978,
0.4496113296546066, 0.4275550934302822, 0.4052413140049899, 0.3826834323650898,
0.3598950365349883, 0.3368898533922201, 0.3136817403988916, 0.2902846772544623,
0.2667127574748984, 0.2429801799032640, 0.2191012401568698, 0.1950903220161283,
0.1709618887603014, 0.1467304744553617, 0.1224106751992163, 0.0980171403295608,
0.0735645635996675, 0.0490676743274181, 0.0245412285229123, 0.0,
};
real cordic(real Q, char cos_or_sin) { // Q的单位是弧度
short sinSign = 1, cosSign = 1;
if (Q < 0)
{
Q = -Q;
sinSign = -1;
}
int n = (int)(Q * d2_pi);
Q -= n * pi_2; // 减去pi/2的整数倍
switch (n % 4) {
case 1: // 去掉负号的原始的Q是第二象限角
Q = pi_2 - Q;
cosSign = -1;
break;
case 2: // 第三象限角
cosSign = -1;
sinSign *= -1;
break;
case 3: // 第四象限角
Q = pi_2 - Q;
sinSign *= -1;
break;
}
integer x = K, y = 0, temp;
real q = 0.0;
for (uint8_t n = 0; n < numIter; n++) {
if (q < Q) {
temp = x - (y >> n);
y = (x >> n) + y;
x = temp;
q += angles[n];
}
else {
temp = x + (y >> n);
y = y - (x >> n);
x = temp;
q -= angles[n];
}
}
if (cos_or_sin == triangle.cosine)
{
return cosSign * x * scale; // cosQ
}
else
{
return sinSign * y * scale; // sinQ
}
}
#define cordic_sin(Q) cordic((Q), triangle.sine)
#define cordic_cos(Q) cordic((Q), triangle.cosine)
//real cordic_sin(real Q) {
// return cordic(Q, triangle.sine);
//}
//
//real cordic_cos(real Q) {
// return cordic(Q, triangle.cosine);
//}
real taylor_cos_sin(real Q, char cos_or_sin) {
int sinSign = 1, cosSign = 1;
if (Q < 0)
{
Q = -Q;
}
int n = (int)(Q * d2_pi);
Q -= n * pi_2; // 减去pi/2的整数倍
switch (n % 4) {
case 1: // 去掉负号的原始的Q是第二象限角
Q = pi_2 - Q;
cosSign = -1;
break;
case 2: // 第三象限角
cosSign = -1;
sinSign *= -1;
break;
case 3: // 第四象限角
Q = pi_2 - Q;
sinSign *= -1;
break;
}
// 0<= Q <=pi/2
n = (int)(Q * d128_pi); // n=0,1,2,...,63
Q -= n * pi_128;
real Q2 = Q * Q;
#ifdef FMADD
__m128d Q2_128 = _mm_set_sd(Q2);
// 再提高泰勒级数的阶数也无法提高精度了。
__m128d cosSmallQ128 = _mm_set_sd(-1.3888888888888889e-03);
cosSmallQ128 = _mm_fmadd_sd(cosSmallQ128, Q2_128, _mm_set_sd(4.1666666666666667e-02));
cosSmallQ128 = _mm_fmadd_sd(cosSmallQ128, Q2_128, _mm_set_sd(-5.0000000000000000e-01));
cosSmallQ128 = _mm_fmadd_sd(cosSmallQ128, Q2_128, _mm_set_sd(1.0));
real cosSmallQ = _mm_cvtsd_f64(cosSmallQ128);
//---------------------------------------------------
__m128d sinSmallQ128 = _mm_set_sd(8.3333333333333333e-03);
sinSmallQ128 = _mm_fmadd_sd(sinSmallQ128, Q2_128, _mm_set_sd(-1.6666666666666667e-01));
sinSmallQ128 = _mm_fmadd_sd(sinSmallQ128, Q2_128, _mm_set_sd(1.0));
sinSmallQ128 = _mm_mul_sd(sinSmallQ128, _mm_set_sd(Q));
real sinSmallQ = _mm_cvtsd_f64(sinSmallQ128);
#else
real cosSmallQ = -1.3888888888888889e-03;
cosSmallQ = cosSmallQ * Q2 + 4.1666666666666667e-02;
cosSmallQ = cosSmallQ * Q2 - 5.0000000000000000e-01;
cosSmallQ = cosSmallQ * Q2 + 1.0;
//---------------------------------------------------
real sinSmallQ = 8.3333333333333333e-03;
sinSmallQ = sinSmallQ * Q2 - 1.6666666666666667e-01;
sinSmallQ = sinSmallQ * Q2 + 1.0;
sinSmallQ = sinSmallQ * Q;
#endif
if (cos_or_sin == triangle.cosine)
{ // cos(n*pi/128+SmallQ)=cos(n*pi/128)cos(SmallQ)-sin(n*pi/128)sin(SmallQ)
return cosSign * (cosTable[n] * cosSmallQ - cosTable[64 - n] * sinSmallQ);
}
else
{ // sin(n*pi/128+SmallQ)=sin(n*pi/128)cos(SmallQ)+cos(n*pi/128)sin(SmallQ)
return sinSign * (cosTable[n] * sinSmallQ + cosTable[64 - n] * cosSmallQ);
}
}
#define taylor_sin(Q) taylor_cos_sin((Q), triangle.sine)
#define taylor_cos(Q) taylor_cos_sin((Q), triangle.cosine)
//real taylor_sin(real Q) {
// return taylor_cos_sin(Q, triangle.sine);
//}
//
//real taylor_cos(real Q) {
// return taylor_cos_sin(Q, triangle.cosine);
//}
int main() {
real Q;
printf("double,精度测试\n");
for (uint8_t n = 1; n < 16; n++) {
Q = 0.1 * n;
printf(" Q = %f\n", Q);
printf("CORDIC: %16.15f, %16.15f\n", cordic_sin(Q), cordic_cos(Q));
printf("taylor: %16.15f, %16.15f\n", taylor_sin(Q), taylor_cos(Q));
printf("math.h: %16.15f, %16.15f\n", sin(Q), cos(Q));
printf("---------------------------------\n");
}
/
printf("速度测试,VS编译器优化设为 最大优化(优选速度)(/O2) \n");
clock_t start = clock();
double sum = 0.0;
const double N = 1e8;
const double c = 64.32 / N;
for (double i = 1.0; i < N; i += 1.0) {
Q = c * i;
sum = sum + cordic_sin(Q) + cordic_cos(Q);
}
printf("sum=%f, CORDIC_Time: %fs\n", sum, (double)(clock() - start) / CLOCKS_PER_SEC);
start = clock();
sum = 0.0;
for (double i = 1.0; i < N; i += 1.0) {
Q = c * i;
sum = sum + taylor_sin(Q) + taylor_cos(Q);
}
printf("sum=%f, Taylor_Time: %fs\n", sum, (double)(clock() - start) / CLOCKS_PER_SEC);
start = clock();
sum = 0.0;
for (double i = 1.0; i < N; i += 1.0) {
Q = c * i;
sum = sum + sin(Q) + cos(Q);
}
printf("sum=%f, math.h_Time: %fs\n", sum, (double)(clock() - start) / CLOCKS_PER_SEC);
return 0;
}
CPU:Intel Core i7 12700H, 开发环境VS2022,使用双精度计算时,输出结果如下:
double,精度测试
Q = 0.100000
CORDIC: 0.099833416646617, 0.995004165278047
taylor: 0.099833416646828, 0.995004165278026
math.h: 0.099833416646828, 0.995004165278026
---------------------------------
Q = 0.200000
CORDIC: 0.198669330794285, 0.980066577841399
taylor: 0.198669330795061, 0.980066577841242
math.h: 0.198669330795061, 0.980066577841242
---------------------------------
Q = 0.300000
CORDIC: 0.295520206662469, 0.955336489125257
taylor: 0.295520206661340, 0.955336489125606
math.h: 0.295520206661340, 0.955336489125606
---------------------------------
Q = 0.400000
CORDIC: 0.389418342309467, 0.921060994002540
taylor: 0.389418342308651, 0.921060994002885
math.h: 0.389418342308651, 0.921060994002885
---------------------------------
Q = 0.500000
CORDIC: 0.479425538604363, 0.877582561890286
taylor: 0.479425538604203, 0.877582561890373
math.h: 0.479425538604203, 0.877582561890373
---------------------------------
Q = 0.600000
CORDIC: 0.564642473394510, 0.825335614910038
taylor: 0.564642473395035, 0.825335614909678
math.h: 0.564642473395035, 0.825335614909678
---------------------------------
Q = 0.700000
CORDIC: 0.644217687238764, 0.764842187283585
taylor: 0.644217687237691, 0.764842187284488
math.h: 0.644217687237691, 0.764842187284488
---------------------------------
Q = 0.800000
CORDIC: 0.717356090900460, 0.696706709346200
taylor: 0.717356090899523, 0.696706709347165
math.h: 0.717356090899523, 0.696706709347165
---------------------------------
Q = 0.900000
CORDIC: 0.783326909627326, 0.621609968270863
taylor: 0.783326909627484, 0.621609968270664
math.h: 0.783326909627483, 0.621609968270664
---------------------------------
Q = 1.000000
CORDIC: 0.841470984807630, 0.540302305868554
taylor: 0.841470984807897, 0.540302305868140
math.h: 0.841470984807897, 0.540302305868140
---------------------------------
Q = 1.100000
CORDIC: 0.891207360060892, 0.453596121426645
taylor: 0.891207360061436, 0.453596121425577
math.h: 0.891207360061435, 0.453596121425577
---------------------------------
Q = 1.200000
CORDIC: 0.932039085967490, 0.362357754475995
taylor: 0.932039085967227, 0.362357754476673
math.h: 0.932039085967226, 0.362357754476673
---------------------------------
Q = 1.300000
CORDIC: 0.963558185417581, 0.267498828623190
taylor: 0.963558185417193, 0.267498828624587
math.h: 0.963558185417193, 0.267498828624587
---------------------------------
Q = 1.400000
CORDIC: 0.985449729988356, 0.169967142900846
taylor: 0.985449729988460, 0.169967142900241
math.h: 0.985449729988460, 0.169967142900241
---------------------------------
Q = 1.500000
CORDIC: 0.997494986603962, 0.070737201669002
taylor: 0.997494986604054, 0.070737201667703
math.h: 0.997494986604054, 0.070737201667703
---------------------------------
速度测试,VS编译器优化设为 最大优化(优选速度)(/O2)
sum=2975793.653839, CORDIC_Time: 22.525000s
sum=2975793.653839, Taylor_Time: 0.965000s
sum=2975793.653839, math.h_Time: 0.933000s
Arduino nano(Atmel 328P)上的代码和结果如下:
// K=0.6072529350088812561694467525049282631124
constexpr int32_t K = 607252935;
// 2^32 =4294967296
constexpr float scale = 1e-9f;
constexpr uint8_t numIter = 25;
constexpr float pi_2 = 1.5707964f; // pi/2
constexpr float d2_pi = 0.63661975f; // 2/pi
constexpr float pi_128 = 0.024543693f; // pi/128
constexpr float d128_pi = 40.743664f; // 128/pi
constexpr int32_t pi_2x1e8 = 157079633; // pi/2 * 1e8
struct {
const char cosine = 0;
const char sine = 1;
}triangle;
// [atan(1), atan(1/2), atan(1/4), atan(1/8), atan(1/16), atan(1/32), atan(1/64), ...]*1e8
constexpr int32_t anglesx1e8[27] = {
78539816, 46364761, 24497866, 12435499,
6241881, 3123983, 1562373, 781234,
390623, 195312, 97656, 48828,
24414, 12207, 6104, 3052,
1526, 763, 381, 191,
95, 48, 24, 12,
6, 3, 1 };
// cos(0),cos(pi/128),cos(2*pi/128),...,cos(63*pi/128),cos(pi/2)
constexpr float cosTable[65] = {
1.0f,
0.99969882f, 0.99879546f, 0.99729046f, 0.99518473f,
0.99247953f, 0.98917651f, 0.98527764f, 0.98078528f,
0.97570213f, 0.97003125f, 0.96377607f, 0.95694034f,
0.94952818f, 0.94154407f, 0.93299280f, 0.92387953f,
0.91420976f, 0.90398929f, 0.89322430f, 0.88192126f,
0.87008699f, 0.85772861f, 0.84485357f, 0.83146961f,
0.81758481f, 0.80320753f, 0.78834643f, 0.77301045f,
0.75720885f, 0.74095113f, 0.72424708f, 0.70710678f,
0.68954054f, 0.67155895f, 0.65317284f, 0.63439328f,
0.61523159f, 0.59569930f, 0.57580819f, 0.55557023f,
0.53499762f, 0.51410274f, 0.49289819f, 0.47139674f,
0.44961133f, 0.42755509f, 0.40524131f, 0.38268343f,
0.35989504f, 0.33688985f, 0.31368174f, 0.29028468f,
0.26671276f, 0.24298018f, 0.21910124f, 0.19509032f,
0.17096189f, 0.14673047f, 0.12241068f, 0.09801714f,
0.07356456f, 0.04906767f, 0.02454123f, 0.0f
};
float cordic(float Q, char cos_or_sin) { // Q的单位是弧度
int sinSign = 1, cosSign = 1;
if (Q < 0)
{
Q = -Q;
sinSign = -1;
}
const int32_t n = (int32_t)(Q * d2_pi);
Q -= n * pi_2; // 减去pi/2的整数倍
int32_t intQ = Q * 1e8f;
switch (n % 4) {
case 1: // 去掉负号的原始的Q是第二象限角
intQ = pi_2x1e8 - intQ;
cosSign = -1;
break;
case 2: // 第三象限角
cosSign = -1;
sinSign *= -1;
break;
case 3: // 第四象限角
intQ = pi_2x1e8 - intQ;
sinSign *= -1;
break;
}
int32_t x = K, y = 0, temp;
int32_t q = 0;
for (uint8_t n = 0; n < numIter; n++) {
if (q < intQ) {
temp = x - (y >> n);
y = (x >> n) + y;
x = temp;
q += anglesx1e8[n];
}
else {
temp = x + (y >> n);
y = y - (x >> n);
x = temp;
q -= anglesx1e8[n];
}
}
if (cos_or_sin == triangle.cosine)
{
return cosSign * x * scale; // cosQ
}
else
{
return sinSign * y * scale; // sinQ
}
}
#define cordic_sin(Q) cordic((Q), triangle.sine)
#define cordic_cos(Q) cordic((Q), triangle.cosine)
float taylor_cos_sin(float Q, char cos_or_sin) {
int sinSign = 1, cosSign = 1;
if (Q < 0)
{
Q = -Q;
}
int n = (int)(Q * d2_pi);
Q -= n * pi_2; // 减去pi/2的整数倍
switch (n % 4) {
case 1: // 去掉负号的原始的Q是第二象限角
Q = pi_2 - Q;
cosSign = -1;
break;
case 2: // 第三象限角
cosSign = -1;
sinSign *= -1;
break;
case 3: // 第四象限角
Q = pi_2 - Q;
sinSign *= -1;
break;
}
// 0<= Q <=pi/2
n = (int)(Q * d128_pi); // n=0,1,2,...,63
Q -= n * pi_128;
float Q2 = Q * Q;
float cosSmallQ = -1.3888889e-03f;
cosSmallQ = cosSmallQ * Q2 + 4.1666668e-02f;
cosSmallQ = cosSmallQ * Q2 - 0.5f;
cosSmallQ = cosSmallQ * Q2 + 1.0f;
//---------------------------------------------------
float sinSmallQ = 8.3333333e-03f;
sinSmallQ = sinSmallQ * Q2 - 1.6666667e-01f;
sinSmallQ = sinSmallQ * Q2 + 1.0f;
sinSmallQ = sinSmallQ * Q;
if (cos_or_sin == triangle.cosine)
{ // cos(n*pi/128+SmallQ)=cos(n*pi/128)cos(SmallQ)-sin(n*pi/128)sin(SmallQ)
return cosSign * (cosTable[n] * cosSmallQ - cosTable[64 - n] * sinSmallQ);
}
else
{ // sin(n*pi/128+SmallQ)=sin(n*pi/128)cos(SmallQ)+cos(n*pi/128)sin(SmallQ)
return sinSign * (cosTable[n] * sinSmallQ + cosTable[64 - n] * cosSmallQ);
}
}
#define taylor_sin(Q) taylor_cos_sin((Q), triangle.sine)
#define taylor_cos(Q) taylor_cos_sin((Q), triangle.cosine)
void setup() {
Serial.begin(9600);
}
void loop() {
float Q;
Serial.println("Accuracy Test");
for (uint8_t n = 1; n < 16; n++) {
Q = 0.1 * n;
Serial.println("Q = " + String(Q, 4));
Serial.println("CORDIC: sin(Q) = " + String(cordic_sin(Q), 7) + ", cos(Q) = " + String(cordic_cos(Q), 7));
Serial.println("taylor: sin(Q) = " + String(taylor_sin(Q), 7) + ", cos(Q) = " + String(taylor_cos(Q), 7));
Serial.println("math.h: sin(Q) = " + String(sin(Q), 7) + ", cos(Q) = " + String(cos(Q), 7));
Serial.println("---------------------------------");
}
/
Serial.println("Speed Test");
float start = millis();
float sum = 0.0;
const int N = 3000;
const float c = 6.432 / N;
for (int i = 1; i < N; i++) {
Q = c * i;
sum = sum + cordic_sin(Q) + cordic_cos(Q);
}
start = (millis() - start) / 1000.0f;
Serial.print("sum = " + String(sum, 7) + ",\t CORDIC_Time:" + String(start, 3) + "s\n");
start = millis();
sum = 0.0;
for (int i = 1; i < N; i++) {
Q = c * i;
sum = sum + taylor_sin(Q) + taylor_cos(Q);
}
start = (millis() - start) / 1000.0f;
Serial.print("sum = " + String(sum, 7) + ",\t taylor_Time:" + String(start, 3) + "s\n");
start = millis();
sum = 0.0;
for (int i = 1; i < N; i++) {
Q = c * i;
sum = sum + sin(Q) + cos(Q);
}
start = (millis() - start) / 1000.0f;
Serial.print("sum = " + String(sum, 7) + ",\t math.h_Time:" + String(start, 3) + "s\n");
}
Accuracy Test
Q = 0.1000
CORDIC: sin(Q) = 0.0998334, cos(Q) = 0.9950041
taylor: sin(Q) = 0.0998334, cos(Q) = 0.9950041
math.h: sin(Q) = 0.0998334, cos(Q) = 0.9950042
---------------------------------
Q = 0.2000
CORDIC: sin(Q) = 0.1986693, cos(Q) = 0.9800665
taylor: sin(Q) = 0.1986693, cos(Q) = 0.9800665
math.h: sin(Q) = 0.1986693, cos(Q) = 0.9800665
---------------------------------
Q = 0.3000
CORDIC: sin(Q) = 0.2955202, cos(Q) = 0.9553365
taylor: sin(Q) = 0.2955202, cos(Q) = 0.9553365
math.h: sin(Q) = 0.2955202, cos(Q) = 0.9553365
---------------------------------
Q = 0.4000
CORDIC: sin(Q) = 0.3894184, cos(Q) = 0.9210610
taylor: sin(Q) = 0.3894183, cos(Q) = 0.9210610
math.h: sin(Q) = 0.3894183, cos(Q) = 0.9210610
---------------------------------
Q = 0.5000
CORDIC: sin(Q) = 0.4794255, cos(Q) = 0.8775826
taylor: sin(Q) = 0.4794255, cos(Q) = 0.8775826
math.h: sin(Q) = 0.4794255, cos(Q) = 0.8775826
---------------------------------
Q = 0.6000
CORDIC: sin(Q) = 0.5646425, cos(Q) = 0.8253355
taylor: sin(Q) = 0.5646425, cos(Q) = 0.8253356
math.h: sin(Q) = 0.5646425, cos(Q) = 0.8253356
---------------------------------
Q = 0.7000
CORDIC: sin(Q) = 0.6442177, cos(Q) = 0.7648422
taylor: sin(Q) = 0.6442177, cos(Q) = 0.7648422
math.h: sin(Q) = 0.6442177, cos(Q) = 0.7648422
---------------------------------
Q = 0.8000
CORDIC: sin(Q) = 0.7173561, cos(Q) = 0.6967067
taylor: sin(Q) = 0.7173560, cos(Q) = 0.6967067
math.h: sin(Q) = 0.7173561, cos(Q) = 0.6967067
---------------------------------
Q = 0.9000
CORDIC: sin(Q) = 0.7833269, cos(Q) = 0.6216100
taylor: sin(Q) = 0.7833269, cos(Q) = 0.6216099
math.h: sin(Q) = 0.7833269, cos(Q) = 0.6216099
---------------------------------
Q = 1.0000
CORDIC: sin(Q) = 0.8414710, cos(Q) = 0.5403023
taylor: sin(Q) = 0.8414709, cos(Q) = 0.5403023
math.h: sin(Q) = 0.8414710, cos(Q) = 0.5403023
---------------------------------
Q = 1.1000
CORDIC: sin(Q) = 0.8912073, cos(Q) = 0.4535961
taylor: sin(Q) = 0.8912073, cos(Q) = 0.4535962
math.h: sin(Q) = 0.8912073, cos(Q) = 0.4535961
---------------------------------
Q = 1.2000
CORDIC: sin(Q) = 0.9320391, cos(Q) = 0.3623576
taylor: sin(Q) = 0.9320391, cos(Q) = 0.3623577
math.h: sin(Q) = 0.9320391, cos(Q) = 0.3623577
---------------------------------
Q = 1.3000
CORDIC: sin(Q) = 0.9635582, cos(Q) = 0.2674988
taylor: sin(Q) = 0.9635582, cos(Q) = 0.2674988
math.h: sin(Q) = 0.9635581, cos(Q) = 0.2674988
---------------------------------
Q = 1.4000
CORDIC: sin(Q) = 0.9854497, cos(Q) = 0.1699672
taylor: sin(Q) = 0.9854497, cos(Q) = 0.1699672
math.h: sin(Q) = 0.9854497, cos(Q) = 0.1699672
---------------------------------
Q = 1.5000
CORDIC: sin(Q) = 0.9974949, cos(Q) = 0.0707372
taylor: sin(Q) = 0.9974950, cos(Q) = 0.0707373
math.h: sin(Q) = 0.9974949, cos(Q) = 0.0707372
---------------------------------
Speed Test
sum = 73.2423320, CORDIC_Time:3.334s
sum = 73.2423170, taylor_Time:1.563s
sum = 73.2423780, math.h_Time:0.750s