Search code examples
javacordic

What's wrong with my CORDIC algorithm?


Adapted to Java from the Wikipedia page on CORDIC:

class MathFunctions {
final static double[] angles = {
    0.78539816339745, 0.46364760900081, 0.24497866312686, 0.12435499454676,
    0.06241880999596, 0.03123983343027, 0.01562372862048, 0.00781234106010,
    0.00390623013197, 0.00195312251648, 0.00097656218956, 0.00048828121119,
    0.00024414062015, 0.00012207031189, 0.00006103515617, 0.00003051757812,
    0.00001525878906, 0.00000762939453, 0.00000381469727, 0.00000190734863,
    0.00000095367432, 0.00000047683716, 0.00000023841858, 0.00000011920929,
    0.00000005960464, 0.00000002980232, 0.00000001490116, 0.00000000745058};
final static double[] Kvalues = {
    0.70710678118655, 0.63245553203368, 0.61357199107790, 0.60883391251775,
    0.60764825625617, 0.60735177014130, 0.60727764409353, 0.60725911229889,
    0.60725447933256, 0.60725332108988, 0.60725303152913, 0.60725295913894,
    0.60725294104140, 0.60725293651701, 0.60725293538591, 0.60725293510314,
    0.60725293503245, 0.60725293501477, 0.60725293501035, 0.60725293500925,
    0.60725293500897, 0.60725293500890, 0.60725293500889, 0.60725293500888};
public static double[] cordic(double theta, int n) {
    double[] v = new double[2];
    if (theta < -Math.PI/2 || theta > Math.PI/2) {
        v = (theta < 0)? cordic(theta + Math.PI, n):cordic(theta - Math.PI, n);
        return new double[]{-v[0],-v[1]};
    }
    double angle=angles[0], Kn=Kvalues[Math.min(n, Kvalues.length-1)];
    double sigma, factor, poweroftwo=1;
    for (int i=0; i<n-1; i++) {
        sigma = (theta < 0)? -1 : 1;
        factor = sigma*poweroftwo;
        v = new double[]{v[0] - v[1]*factor, v[0]*factor + v[1]};
        theta -= sigma*angle;
        poweroftwo /= 2;
        angle = (i+2 > angles.length)? angle/2 : angles[i+2];
    }
    return new double[]{v[0]*Kn, v[1]*Kn};
}}

I just tested the code with cos PI like this:

double cosPI = MathFunctions.cordic(Math.PI, 8)[0];
System.out.printf("cos(PI) = %f%n",cosPI);

and for some reason it gave me -0.0 instead of -1.


Solution

  • The short answer is that you didn't initialize the v vector properly. Updated code is below. Note that on java this still isn't very accurate.

    class MathFunctions {
      final static double[] angles = {
        0.78539816339745d, 0.46364760900081d, 0.24497866312686d, 0.12435499454676d,
        0.06241880999596d, 0.03123983343027d, 0.01562372862048d, 0.00781234106010d,
        0.00390623013197d, 0.00195312251648d, 0.00097656218956d, 0.00048828121119d,
        0.00024414062015d, 0.00012207031189d, 0.00006103515617d, 0.00003051757812d,
        0.00001525878906d, 0.00000762939453d, 0.00000381469727d, 0.00000190734863d,
        0.00000095367432d, 0.00000047683716d, 0.00000023841858d, 0.00000011920929d,
        0.00000005960464d, 0.00000002980232d, 0.00000001490116d, 0.00000000745058d};
      final static double[] Kvalues = {
        0.70710678118655d, 0.63245553203368d, 0.61357199107790d, 0.60883391251775d,
        0.60764825625617d, 0.60735177014130d, 0.60727764409353d, 0.60725911229889d,
        0.60725447933256d, 0.60725332108988d, 0.60725303152913d, 0.60725295913894d,
        0.60725294104140d, 0.60725293651701d, 0.60725293538591d, 0.60725293510314d,
        0.60725293503245d, 0.60725293501477d, 0.60725293501035d, 0.60725293500925d,
        0.60725293500897d, 0.60725293500890d, 0.60725293500889d, 0.60725293500888d};
    
      public static double[] cordic(double theta, int n) {
        double[] v;
        if (theta < -Math.PI/2 || theta > Math.PI/2) {
          v = (theta < 0)? cordic(theta + Math.PI, n):cordic(theta - Math.PI, n);
          return new double[]{-v[0],-v[1]};
        }
        // You didn't initialise v properly
        v = new double[] {1.0d, 0, };
        double angle=angles[0], Kn=Kvalues[Math.min(n, Kvalues.length-1)];
        double sigma, factor, poweroftwo=1;
        for (int i=0; i<n; i++) {
          sigma = (theta < 0)? -1 : 1;
          factor = sigma*poweroftwo;
          v = new double[]{v[0] - v[1]*factor, v[0]*factor + v[1]};
          theta -= sigma*angle;
          poweroftwo /= 2;
          angle = (i+2 > angles.length)? angle/2 : angles[i+2];
        }
        return new double[]{v[0]*Kn, v[1]*Kn};
      }
    
      public static void main(String[] args)
      {
        double[] values;
        values = MathFunctions.cordic(Math.PI, 8);
        System.out.printf("cos(PI)   = %f, sin(PI)   = %f%n",values[0], values[1]);
        values = MathFunctions.cordic(Math.PI/2, 8);
        System.out.printf("cos(PI/2) = %f, sin(PI/2) = %f%n",values[0], values[1]);
        values = MathFunctions.cordic(0, 15);
        System.out.printf("cos(0)    = %f, sin(0)    = %f%n",values[0], values[1]);
      }
    }