Arduboyで狙い撃つぜ!(atan2テーブルの作り方) その13

前回のコードを参考に、過去のコードを高速化した。


元のコード
raohu69.hatenablog.jp

const uint8_t atanTbl[] PROGMEM = {
  0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 
  2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 
  5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 
  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 
  8, 
};

uint8_t getAtan2(float y, float x)
{
  int8_t idx = 0; // 0度
  if (x == 0.f && y == 0.f) return idx; // 同じ位置の時は0度とみなす

  float ax = abs(x);
  float ay = abs(y);

  if (ax > ay) {
    uint8_t ratio = ay / ax * 64;
    idx = pgm_read_byte(atanTbl + ratio);
  } else {
    uint8_t ratio = ax / ay * 64;
    idx = 16 - pgm_read_byte(atanTbl + ratio);
  }

  // idxは第1象限の値なので、実際の象限の値に調整する
  if (x < 0) idx = 32 - idx;
  if (y < 0) idx = 64 - idx;

  return idx;
}


高速化したコード

const uint8_t atanTbl[] PROGMEM = {
  0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 
  2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 
  5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 
  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 
  8, 
};
const int8_t atanOffset[] PROGMEM = {
  0, 32, 0, 32, 
};

uint8_t getAtan2(float y, float x)
{
  uint8_t idx = 0; // 0度
  if (x == 0.f && y == 0.f) return idx; // 同じ位置の時は0度とみなす

  uint8_t offset = 0;
  if (x < 0.f) {
    x = -x;
    offset |= 1;
  }
  if (y < 0.f) {
    y = -y;
    offset |= 2;
  }

  if (x > y) {
    uint8_t ratio = y / x * 64;
    idx = pgm_read_byte(atanTbl + ratio);
  } else {
    uint8_t ratio = x / y * 64;
    idx = 16 - pgm_read_byte(atanTbl + ratio);
  }

  if (((offset + 1) & 2) != 0) {
    idx = -idx;
  }

  return idx + pgm_read_byte(atanOffset + offset);
}


過去のコードでは象限を求めるためにif文が2回必要だったが、1回で済ますことができた。