3 * The original code was published in Docter Dobbs Journal issue ddj9010.
4 * The ddj version can be obtained using FTP from SIMTEL and other places.
6 * Converted to ANSI-C (with prototypes) by P. Knoppers, 13-Apr-1992.
8 * The main advantage of the CORDIC algorithms is that all commonly used math
9 * functions ([a]sin[h] [a]cos[h] [a]tan[h] atah[h](y/x) ln exp sqrt) are
10 * implemented using only shift, add, subtract and compare. All values are
11 * treated as integers. Actually they are fixed point floating point values.
12 * The position of the fixed point is a compile time constant (fractionBits).
13 * I don't believe that this can be easily fixed...
15 * Some initialization of internal tables and constants is necessary before
16 * all functions can be used. The constant "HalfPi" must be determined before
17 * compile time, all others are computed during run-time - see main() below.
19 * Of course, any serious implementation of these functions should probably
20 * have _all_ constants determined sometime before run-time and most
21 * functions might be written in assembler.
24 * The layout of the code is adapted to my personal preferences.
28 /* Prototypes: (these should be moved to a separate include file) */
30 void WriteVarious (long n);
31 void WriteFraction (long n);
32 long Reciprocal (unsigned n, unsigned k);
33 long Poly2 (int log, unsigned n);
34 void Circular (long x, long y, long z);
35 void WriteRegisters (void);
36 long ScaledReciprocal (long n, unsigned k);
37 void InvertCircular (long x, long y, long z);
38 void Hyperbolic (long x, long y, long z);
39 void Linear (long x, long y, long z);
40 void InvertHyperbolic (long x, long y, long z);
43 * _IMPLEMENTING CORDIC ALGORITHMS_
51 * cordicC.c -- J. Pitts Jarvis, III
53 * cordicC.c computes CORDIC constants and exercises the basic algorithms.
54 * Represents all numbers in fixed point notation. 1 bit sign,
55 * longBits-1-n bit integral part, and n bit fractional part. n=29 lets us
56 * represent numbers in the interval [-4, 4) in 32 bit long. Two's
57 * complement arithmetic is operative here.
60 #define fractionBits 29
62 #define One (010000000000L>>1)
63 #define HalfPi (014441766521L>>1)
66 * cordic algorithm identities for circular functions, starting with [x, y, z]
68 * driving z to 0 gives: [P*(x*cos(z)-y*sin(z)), P*(y*cos(z)+x*sin(z)), 0]
69 * driving y to 0 gives: [P*sqrt(x^2+y^2), 0, z+atan(y/x)]
70 * where K = 1/P = sqrt(1+1)* . . . *sqrt(1+(2^(-2*i)))
71 * special cases which compute interesting functions
72 * sin, cos [K, 0, a] -> [cos(a), sin(a), 0]
73 * atan [1, a, 0] -> [sqrt(1+a^2)/K, 0, atan(a)]
74 * [x, y, 0] -> [sqrt(x^2+y^2)/K, 0, atan(y/x)]
75 * for hyperbolic functions, starting with [x, y, z] and then
76 * driving z to 0 gives: [P*(x*cosh(z)+y*sinh(z)), P*(y*cosh(z)+x*sinh(z)), 0]
77 * driving y to 0 gives: [P*sqrt(x^2-y^2), 0, z+atanh(y/x)]
78 * where K = 1/P = sqrt(1-(1/2)^2)* . . . *sqrt(1-(2^(-2*i)))
79 * sinh, cosh [K, 0, a] -> [cosh(a), sinh(a), 0]
80 * exponential [K, K, a] -> [e^a, e^a, 0]
81 * atanh [1, a, 0] -> [sqrt(1-a^2)/K, 0, atanh(a)]
82 * [x, y, 0] -> [sqrt(x^2-y^2)/K, 0, atanh(y/x)]
83 * ln [a+1, a-1, 0] -> [2*sqrt(a)/K, 0, ln(a)/2]
84 * sqrt [a+(K/2)^2, a-(K/2)^2, 0] -> [sqrt(a), 0, ln(a*(2/K)^2)/2]
85 * sqrt, ln [a+(K/2)^2, a-(K/2)^2, -ln(K/2)] -> [sqrt(a), 0, ln(a)/2]
86 * for linear functions, starting with [x, y, z] and then
87 * driving z to 0 gives: [x, y+x*z, 0]
88 * driving y to 0 gives: [x, 0, z+y/x]
91 long X0C, X0H, X0R; /* seed for circular, hyperbolic, and square
93 long OneOverE, E; /* the base of natural logarithms */
94 long HalfLnX0R; /* constant used in simultanous sqrt, ln
98 * compute atan(x) and atanh(x) using infinite series
99 * atan(x) = x - x^3/3 + x^5/5 - x^7/7 + . . . for x^2 < 1
100 * atanh(x) = x + x^3/3 + x^5/5 + x^7/7 + . . . for x^2 < 1
101 * To calcuate these functions to 32 bits of precision, pick
102 * terms[i] s.t. ((2^-i)^(terms[i]))/(terms[i]) < 2^-32
103 * For x <= 2^(-11), atan(x) = atanh(x) = x with 32 bits of accuracy
106 static unsigned terms[11] = {0, 27, 14, 9, 7, 5, 4, 4, 3, 3, 3};
108 static long atan[fractionBits + 1];
109 static long atanh[fractionBits + 1];
114 #include <stdio.h> /* putchar is a marco for some */
116 /* Delta is inefficient but pedagogical */
117 #define Delta(n, Z) (Z >= 0) ? (n) : -(n)
118 #define abs(n) (n >= 0) ? (n) : -(n)
121 * Reciprocal, calculate reciprocol of n to k bits of precision
122 * a and r form integer and fractional parts of the dividend respectively
124 long Reciprocal (unsigned n, unsigned k)
130 for (i = 0; i <= k; ++i)
140 return (a >= n ? r + 1 : r);/* round result */
143 /* ScaledReciprocal, n comes in funny fixed point fraction representation */
144 long ScaledReciprocal (long n, unsigned k)
151 for (i = 0; i <= k; ++i)
161 return (a >= n ? r + 1 : r);/* round result */
165 * Poly2 calculates polynomial where the variable is an integral power of 2,
166 * log is the power of 2 of the variable
167 * n is the order of the polynomial
168 * coefficients are in the array a[]
170 long Poly2 (int log, unsigned n)
175 for (i = n; i >= 0; --i)
176 r = (log < 0 ? r >> -log : r << log) + a[i];
180 void WriteFraction (long n)
184 unsigned short digit;
187 putchar (n < 0 ? '-' : ' ');
189 putchar ((n >> fractionBits) + '0');
191 low = k = n << (longBits - fractionBits); /* align octal point at left */
192 k >>= 4; /* shift to make room for a decimal digit */
193 for (i = 1; i <= 8; ++i)
195 digit = (k *= 10L) >> (longBits - 4);
196 low = (low & 0xf) * 10;
197 k += ((unsigned long) (low >> 4)) -
198 ((unsigned long) digit << (longBits - 4));
199 putchar (digit + '0');
203 void WriteRegisters (void)
213 void WriteVarious (long n)
216 printf (" 0x%08lx 0%011lo\n", n, n);
219 void Circular (long x, long y, long z)
227 for (i = 0; i <= fractionBits; ++i)
238 void InvertCircular (long x, long y, long z)
246 for (i = 0; i <= fractionBits; ++i)
257 void Hyperbolic (long x, long y, long z)
265 for (i = 1; i <= fractionBits; ++i)
273 if ((i == 4) || (i == 13))
285 void InvertHyperbolic (long x, long y, long z)
292 for (i = 1; i <= fractionBits; ++i)
300 if ((i == 4) || (i == 13))
312 void Linear (long x, long y, long z)
321 for (i = 1; i <= fractionBits; ++i)
330 void InvertLinear (long x, long y, long z)
339 for (i = 1; i <= fractionBits; ++i)
341 Z -= Delta (z >>= 1, -Y);
342 Y += Delta (x >>= 1, -Y);
346 /*********************************************************/
348 int main (int argc, char *argv[])
353 /* system("date"); *//* time stamp the log for UNIX systems */
355 for (i = 0; i <= 13; ++i)
358 a[2 * i + 1] = Reciprocal (2 * i + 1, fractionBits);
360 for (i = 0; i <= 10; ++i)
361 atanh[i] = Poly2 (-i, terms[i]);
362 atan[0] = HalfPi / 2; /* atan(2^0)= pi / 4 */
363 for (i = 1; i <= 7; ++i)
364 a[4 * i - 1] = -a[4 * i - 1];
365 for (i = 1; i <= 10; ++i)
366 atan[i] = Poly2 (-i, terms[i]);
367 for (i = 11; i <= fractionBits; ++i)
368 atan[i] = atanh[i] = 1L << (fractionBits - i);
370 printf ("\natanh(2^-n)\n");
371 for (i = 1; i <= 10; ++i)
374 WriteVarious (atanh[i]);
378 for (i = 1; i <= fractionBits; ++i)
380 r += atanh[4] + atanh[13];
381 printf ("radius of convergence");
383 printf ("\n\natan(2^-n)\n");
384 for (i = 0; i <= 10; ++i)
387 WriteVarious (atan[i]);
391 for (i = 0; i <= fractionBits; ++i)
393 printf ("radius of convergence");
396 /* all the results reported in the printfs are calculated with my HP-41C */
397 printf ("\n\n--------------------circular functions--------------------\n");
399 printf ("Grinding on [1, 0, 0]\n");
400 Circular (One, 0L, 0L);
403 WriteVarious (X0C = ScaledReciprocal (X, fractionBits));
405 printf ("\nGrinding on [K, 0, 0]\n");
406 Circular (X0C, 0L, 0L);
409 printf ("\nGrinding on [K, 0, pi/6] -> [0.86602540, 0.50000000, 0]\n");
410 Circular (X0C, 0L, HalfPi / 3L);
413 printf ("\nGrinding on [K, 0, pi/4] -> [0.70710678, 0.70710678, 0]\n");
414 Circular (X0C, 0L, HalfPi / 2L);
417 printf ("\nGrinding on [K, 0, pi/3] -> [0.50000000, 0.86602540, 0]\n");
418 Circular (X0C, 0L, 2L * (HalfPi / 3L));
421 printf ("\n------Inverse functions------\n");
423 printf ("Grinding on [1, 0, 0]\n");
424 InvertCircular (One, 0L, 0L);
427 printf ("\nGrinding on [1, 1/2, 0] -> [1.84113394, 0, 0.46364761]\n");
428 InvertCircular (One, One / 2L, 0L);
431 printf ("\nGrinding on [2, 1, 0] -> [3.68226788, 0, 0.46364761]\n");
432 InvertCircular (One * 2L, One, 0L);
435 printf ("\nGrinding on [1, 5/8, 0] -> [1.94193815, 0, 0.55859932]\n");
436 InvertCircular (One, 5L * (One / 8L), 0L);
439 printf ("\nGrinding on [1, 1, 0] -> [2.32887069, 0, 0.78539816]\n");
440 InvertCircular (One, One, 0L);
443 printf ("\n--------------------hyperbolic functions--------------------\n");
445 printf ("Grinding on [1, 0, 0]\n");
446 Hyperbolic (One, 0L, 0L);
449 WriteVarious (X0H = ScaledReciprocal (X, fractionBits));
452 Linear (X0R, 0L, X0R);
453 WriteVarious (X0R = Y);
455 printf ("\nGrinding on [K, 0, 0]\n");
456 Hyperbolic (X0H, 0L, 0L);
459 printf ("\nGrinding on [K, 0, 1] -> [1.54308064, 1.17520119, 0]\n");
460 Hyperbolic (X0H, 0L, One);
463 printf ("\nGrinding on [K, K, -1] -> [0.36787944, 0.36787944, 0]\n");
464 Hyperbolic (X0H, X0H, -One);
466 OneOverE = X; /* save value ln(1/e) = -1 */
468 printf ("\nGrinding on [K, K, 1] -> [2.71828183, 2.71828183, 0]\n");
469 Hyperbolic (X0H, X0H, One);
471 E = X; /* save value ln(e) = 1 */
473 printf ("\n------Inverse functions------\n");
475 printf ("Grinding on [1, 0, 0]\n");
476 InvertHyperbolic (One, 0L, 0L);
479 printf ("\nGrinding on [1/e + 1, 1/e - 1, 0] -> [1.00460806, 0, -0.50000000]\n");
480 InvertHyperbolic (OneOverE + One, OneOverE - One, 0L);
483 printf ("\nGrinding on [e + 1, e - 1, 0] -> [2.73080784, 0, 0.50000000]\n");
484 InvertHyperbolic (E + One, E - One, 0L);
487 printf ("\nGrinding on (1/2)*ln(3) -> [0.71720703, 0, 0.54930614]\n");
488 InvertHyperbolic (One, One / 2L, 0L);
491 printf ("\nGrinding on [3/2, -1/2, 0] -> [1.17119417, 0, -0.34657359]\n");
492 InvertHyperbolic (One + (One / 2L), -(One / 2L), 0L);
495 printf ("\nGrinding on sqrt(1/2) -> [0.70710678, 0, 0.15802389]\n");
496 InvertHyperbolic (One / 2L + X0R, One / 2L - X0R, 0L);
499 printf ("\nGrinding on sqrt(1) -> [1.00000000, 0, 0.50449748]\n");
500 InvertHyperbolic (One + X0R, One - X0R, 0L);
504 printf ("\nGrinding on sqrt(2) -> [1.41421356, 0, 0.85117107]\n");
505 InvertHyperbolic (One * 2L + X0R, One * 2L - X0R, 0L);
508 printf ("\nGrinding on sqrt(1/2), ln(1/2)/2 -> [0.70710678, 0, -0.34657359]\n");
509 InvertHyperbolic (One / 2L + X0R, One / 2L - X0R, -HalfLnX0R);
512 printf ("\nGrinding on sqrt(3)/2, ln(3/4)/2 -> [0.86602540, 0, -0.14384104]\n");
513 InvertHyperbolic ((3L * One / 4L) + X0R, (3L * One / 4L) - X0R, -HalfLnX0R);
516 printf ("\nGrinding on sqrt(2), ln(2)/2 -> [1.41421356, 0, 0.34657359]\n");
517 InvertHyperbolic (One * 2L + X0R, One * 2L - X0R, -HalfLnX0R);
528 1 0.54930614 0x1193ea7a 002144765172
529 2 0.25541281 0x082c577d 001013053575
530 3 0.12565721 0x04056247 000401261107
531 4 0.06258157 0x0200ab11 000200125421
532 5 0.03126017 0x01001558 000100012530
533 6 0.01562627 0x008002aa 000040001252
534 7 0.00781265 0x00400055 000020000125
535 8 0.00390626 0x0020000a 000010000012
536 9 0.00195312 0x00100001 000004000001
537 10 0.00097656 0x00080000 000002000000
539 radius of convergence 1.11817300
543 0 0.78539816 0x1921fb54 003110375524
544 1 0.46364760 0x0ed63382 001665431602
545 2 0.24497866 0x07d6dd7e 000765556576
546 3 0.12435499 0x03fab753 000376533523
547 4 0.06241880 0x01ff55bb 000177652673
548 5 0.03123983 0x00ffeaad 000077765255
549 6 0.01562372 0x007ffd55 000037776525
550 7 0.00781233 0x003fffaa 000017777652
551 8 0.00390622 0x001ffff5 000007777765
552 9 0.00195312 0x000ffffe 000003777776
553 10 0.00097656 0x0007ffff 000001777777
555 radius of convergence 1.74328660