Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

The CORDIC Method for Faster sin and cos Calculations


November 1992/The CORDIC Method for Faster sin and cos Calculations/Listing 1

Listing 1 CORDIC.C

/*  CORDIC.C : Demonstrates the integer-based CORDIC
 *  system for calculating sines and cosines. The
 *  vertices of a regular hexagon are calculated using
 *  CORDIC trig and the hexagon itself is rotated.
 *  Make in Borland C++'s internal environment.
 *  (c) 1991 Michael Bertrand.
 */

#include <stdio.h>     /* printf */
#include <math.h>      /* sqrt, atan */
#include <conio.h>     /* getch */
#include <graphics.h>  /* BGI */

typedef struct
{
  int x;
  int y;
} POINT;

typedef unsigned int WORD;

void CalcHexPtsCORDIC(POINT center, POINT vertex);
void DrawHexagon(POINT center, POINT vertex);
void DrawCross(POINT pt, int colr);
void SinCosSetup(void);
void SinCos(WORD theta, int *sin, int *cos);

#define ESC 0x1B

/* Quadrants for angles. */
#define QUAD1 1
#define QUAD2 2
#define QUAD3 3
#define QUAD4 4

/* NBITS is number of bits for CORDIC units. */
#define NBITS 14

/* NUM_PTS is number of vertices in polygon. */
#define NUM_PTS 6

int  ArcTan[NBITS];       /* angles for rotation */
int  xInit;               /* initial x projection */
WORD CordicBase;          /* base for CORDIC units */
WORD HalfBase;            /* CordicBase / 2 */
WORD Quad2Boundary;       /* 2 * CordicBase */
WORD Quad3Boundary;       /* 3 * CordicBase */
POINT HexPts[NUM_PTS+1];  /* calculated poly points */

void main(void)
{
  int   driver;   /* for initgraph() */
  int   mode;     /* for initgraph() */
  WORD  theta;    /* CORDIC angle */
  int   sine;     /* sine of CORDIC angle */
  int   cosine;   /* cosine of CORDIC angle */
  POINT center;   /* center of hexagon */
  POINT vertex;   /* hexagon's original base vertex */
  POINT vertex1;  /* hexagon's changing base vertex */
  POINT del;      /* vertex - center (radial spoke) */
  int   radius;   /* radius of circumscribing circle */

  driver = VGA;     /* for initgraph() */
  mode   = VGAHI;   /* mode 0x12 : 640x480 16 color */

  if (registerbgidriver(EGAVGA_driver) < 0)
    {
    printf("couldn't find VGA driver"); return;
    }
  initgraph(&driver, &mode, NULL);

  printf("Press ENTER to rotate, ESC to quit.");

  center.x = 320; center.y = 240;
  vertex.x = 470; vertex.y = 240;
  radius = vertex.x - center.x;
  /* Calculate the radial spoke : vertex - center. */
  del.x = vertex.x - center.x;
  del.y = vertex.y - center.y;

  setwritemode(XOR_PUT);

  /* Draw circumscribing circle. */
  setcolor(RED);
  circle(center.x, center.y, radius);

  /* Draw small cross at center. */
  DrawCross(center, YELLOW);
  setcolor(WHITE);

  /* Setup CORDIC system, initialize theta = 0. */
  SinCosSetup();
  theta = 0;

  /* Draw initial hexagon. */
  DrawHexagon(center, vertex1 = vertex);

  /* Rotate hexagon. vertex is fixed; vertex1 rotates
   * clockwise around vertex in increments of 650
   * CORDIC units (3.57 deg). CORDIC sines/cosines are
   * used to find vertex1. DrawHexagon() also uses
   * CORDIC sines/cosines to calculate the remaining
   * vertices for each hexagon so they can be drawn.
   */

  while (getch() ! = ESC)
    {
    /* Erase last hexagon. */
    DrawHexagon(center, vertex1);
    /* Inc theta by 650 CORDIC units (3.57 deg). */
    theta += 650;
    SinCos(theta, &sine, &cosine);
    /* Calc new vertex by rotating around center. */
    vertex1.x = (int)
      (((long) del.x * cosine - (long) del.y * sine +
      HalfBase) >> NBIIS) + center.x;
    vertexl.y = (int)
      (((long) del.x * sine + (long) del.y * cosine +
      HalfBase) >> NBITS) + center.y;
    /* Draw new hexagon. */
    DrawHexagon(center, vertex1);
    }

  closegraph();
}

void CalcHexPtsCORDIC(POINT center, POINT vertex)
/*
  USE:  Calc array of hex vertices using CORDIC calcs.
  IN:   center = center of hexagon.
       vertex = One of the hexagon vertices
  NOTE: Loads global array HexPoints[] with other 5
   vertices of regular hexagon. Uses CORDIC routines
   for trig and long integer calculations.
*/
{
  int   sine;     /* sine of central angle */
  int   cosine;   /* cosine of central angle */
  int   corner;   /* index for vertices of polygon */
  POINT del;      /* vertex - center (radial spoke) */

  /* 60 deg = 10923 CORDIC units. */
  SinCos(10923, &sine, &cosine);

  /* Set initial and final point to incoming vertex. */
  HexPts[0].x = HexPts[NUM PTS].x = vertex.x;
  HexPts[0].y = HexPts[NUM_PTS].y = vertex.y;

  /* Go clockwise around circle to calc hex points. */
  for (corner = 1; corner < NUM_PTS; corner++)
    {
    /* Calculate the radial spoke : vertex - center. */
    del.x = vertex.x - center.x;
    del.y = vertex.y - center.y;
    /* calc new vertex by rotating around center. */
    vertex.x = (int)
      (((long) del.x * cosine - (long) del.y * sine +
      HalfBase) >> NBITS) + center.x;
    vertex.y = (int)
      (((long) del.x * sine + (long) del.y * cosine +
      HalfBase) >> NBITS) + center.y;
    /* Store new vertex in array. */
    HexPts[corner].x = vertex.x;
    HexPts[corner].y = vertex.y;
    }
}

void DrawHexagon(POINT center, POINT vertex)
/*
  USE:  Draw Hexagon given center and one vertex.
  IN:   center = center of hexagon.
       vertex = one of the hexagon vertices
  NOTE: Call CalcHexPtsCORDIC() to load global array
   HexPts[] with hexagon vertices.
*/
{
  CalcHexPtsCORDIC(center, vertex);
  drawpoly(NUM_PTS+1, (int far *)HexPts);
}

void DrawCross(POINT pt, int colr)
/*
  USE: Draw cross on screen at pt with given color.
*/
{
  int oldColor;

  setwritemode(COPY_PUT);
  oldColor = getcolor();
  setcolor(colr);
  moveto(pt.x - 2, pt.y); lineto(pt.x + 2, pt.y);
  moveto(pt.x, pt.y - 2); lineto(pt.x, pt.y + 2);
  setcolor(oldColor);
  setwritemode(XOR_PUT);
}

void SinCosSetup(void)
/*
  USE : Load globals used by SinCos().
  OUT : Loads globals used in SinCos() :
   CordicBase    = base for CORDIC units
   HalfBase      = Cordicbase / 2
   Quad2Boundary = 2 * CordicBase
   Quad3Boundary = 3 * CordicBase
   ArcTan[]      = the arctans of 1/(2^i)
   xInit         = initial value for x projection
  NOTE: Must be called once only to initialize before
   calling SinCos(). xInit is sufficiently less than
   CordicBase to exactly compensate for the expansion
   in each rotation.
*/
{
  int i;        /* to index ArcTan[] */
  double f;     /* to calc initial x projection */
  long powr;    /* powers of 2 up to 2^(2*(NBITS-1)) */

  CordicBase = 1 << NBITS;
  HalfBase = CordicBase >> 1;
  Quad2Boundary = CordicBase << 1;
  Quad3Boundary = CordicBase + Quad2Boundary;

  /* ArcTan's are diminishingly small angles. */
  powr = 1;
  for (i = 0; i < NBITS; i++)
    {
    ArcTan[i] = (int)
      (atan(1.0/powr)/(M_PI/2)*CordicBase + 0.5);
    powr << = 1;
    }
  /* xInit is initial value of x projection to
   * compensate for expansions. f = 1/sqrt(2/1 * 5/4 * ...
   * Normalize as an NBITS binary fraction (multiply by
   * CordicBase) and store in xInit. Get f = 0.607253
   * and xInit = 9949 = 0x26DD for NBITS = 14.
   */
  f = 1.0;
  powr = 1;
  for (i = 0; i < NBITS; i++)
   {
   f = (f * (powr + 1)) / powr;
   powr <<= 2;
   }
  f = 1.0/sqrt(f);
  xInit = (int) (CordicBase * f + 0.5);
}

void SinCos(WORD theta, int *sin, int *cos)
/*
  USE : Calc sin and cos with integer CORDIC routine.
  IN  : theta = incoming angle (in CORDIC angle units)
  OUT : sin = ptr to sin (in CORDIC fixed point units)
       cos = ptr to cos (in CORDIC fixed point units)
  NOTE: The incoming angle theta is in CORDIC angle
   units, which subdivide the circle into 64K parts,
   with 0 deg = 0, 90 deg = 16384 (CordicBase), 180 deg
   = 32768, 270 deg = 49152, etc. The calculated sine
   and cosine are in CORDIC fixed point units : an int
   considered as a fraction of 16384 (CordicBase).
*/
{
  int quadrant;  /* quadrant of incoming angle */
  int z;         /* incoming angle moved to 1st quad */
  int i;         /* to index rotations : one per bit */
  int x, y;      /* projections onto axes */
  int xl, yl;    /* projections of rotated vector */

  /* Determine quadrant of incoming angle, translate to
   * 1st quadrant. Note use of previously calculated
   * values CordicBase, etc. for speed.
   */

  if (theta < CordicBase)
    {
    quadrant = QUAD1;
    z = (int) theta;
    }
  else if (theta < Quad2Boundary)
    {
    quadrant = QUAD2;
    z = (int) (Quad2Boundary - theta);
    }
  else if (theta < Quad3Boundary)
    {
    quadrant = QUAD3;
    z = (int) (theta - Quad2Boundary);
    }
  else
    {
    quadrant = QUAD4;
    z = - ((int) theta);
    }

  /* Initialize projections. */
  x = xInit;
  y = 0;

  /* Negate z, so same rotations taking angle z to 0
   * will take (x, y) = (xInit, 0) to (*cos, *sin).
   */
  z = -z;

  /* Rotate NBITS times. */
  for (i = 0; i < NBITS; i++)
    {
    if (z < 0)   
      {
      /* Counter-clockwise rotation. */
      z += ArcTan[i];
      y1 = y + (x >> i);
      x1 = x - (y >> i);
      }
    else
      {
      /* Clockwise rotation. */
      z -= ArcTan[i];
      y1 = y - (x >> i);
      x1 = x + (y >> i);
      }

    /* Put new projections into (x,y) for next go. */
    x = x1;
    y = y1;
    }  /* for i */

  /* Attach signs depending on quadrant. */
  *cos = (quadrant==QUAD1 || quadrant==QUAD4) ? x : -x;
  *sin = (quadrant==QUAD1 || quadrant==QUAD2) ? y : -y;
}
/* End of File */


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.