2D IDCT を計算する

# はじめに
2D Inverse Discrete cosine transform(2D IDCT)の計算を説明します。
2D IDCTは画像、動画のデコードに利用されます。

# 2D IDCT
2D IDCTの式を示します。式1とします。F(u,v)はDCT係数です。f(x,y)は画素の色データです。
C(u),C(v)はu,vが0であれば$\frac{1}{\sqrt{N}}$ そうでなければ$\sqrt{\frac{2}{N}}$となります。

```math
f(x,y) = \sum^{N-1}_{u=0}\sum^{N-1}_{v=0}C(u)C(v)\cos\frac{2\pi u(2x+1)}{4N}\cos\frac{2\pi v(2y+1)}{4N}F(u,v)
```

ここでは N=8 とします。8x8 = 64個のF(u,v)から64個のf(u,v)を求めます。

少し式の項を並び替えてC'を考えます。

```math
f(x,y) = \sum^{N-1}_{u=0}\sum^{N-1}_{v=0}C(u)C(v)\cos\frac{2\pi u(2x+1)}{4N}\cos\frac{2\pi v(2y+1)}{4N}F(u,v) \\
C'(x,y,u,v) = C(u)C(v)\cos\frac{2\pi u(2x+1)}{4N}\cos\frac{2\pi v(2y+1)}{4N} \\
f(x,y) = \sum^{N-1}_{u=0}\sum^{N-1}_{v=0} C'(x,y,u,v)F(u,v)
```

C' は 8x8x8x8=4096 個あります。
f(0,0)を求めるためには64回の乗算、63回の加算が必要です。
x, y はそれぞれ8個ある為、
f(x,y)をすべて求めるためには 8x8x64=4096回の乗算、8x8x63=4032回の加算が必要です。

# 1D IDCTに置き換える
式1 は 1D IDCT を 2回繰り返すことにより計算できます。これにより乗算、加算回数を減らすことができます。
u, v に依存する部分をまとめます。式1の$\sum$の位置を移動します。 

```math
f(x,y) = \sum^{N-1}_{u=0}C(u)\cos\frac{2\pi u(2x+1)}{4N}\sum^{N-1}_{v=0}C(v)\cos\frac{2\pi v(2y+1)}{4N}F(u,v)
```

F から F'を求めます。1回目の1D IDCTです。一番下の式を式2とします。
F'(0,0)を求めるためには8回の乗算、7回の加算が必要です。
u, y はそれぞれ8個ある為、F'(u,y)をすべて求めるためには 8x8x8=512回の乗算、8x8x7=448回の加算が必要です。

```math
F'(u,y) = \sum^{N-1}_{v=0}C(v)\cos\frac{2\pi v(2y+1)}{4N}F(u,v) \\
C''(v,y) = C(v)\cos\frac{2\pi v(2y+1)}{4N} \\
F'(u,y) = \sum^{N-1}_{v=0}C''(v,y)F(u,v)
```

次に F' から f を求めます。2回目の1D IDCTです。一番下の式を式3とします。
F' から f(x,y)をすべて求めるためには 8x8x8=512回の乗算、8x8x7=448回の加算が必要です。

```math
f(x,y) = \sum^{N-1}_{u=0}C(u)\cos\frac{2\pi u(2x+1)}{4N}F'(u,y) \\
C'''(u,x) = C(u)\cos\frac{2\pi u(2x+1)}{4N} \\
f(x,y) = \sum^{N-1}_{u=0}C'''(u,x)F'(u,y)
```

# AP-922
次のドキュメントに紹介されているIDCTの手法を説明します。以降ではAP-922といいます。
Application Note 922
A Fast Precise Implementation of 8x8 Discrete Cosine Transform  Using the Streaming SIMD Extensions and MMX Instructions

記号を定義します。式2式3にでてくるC'',C'''は同じものです。以降では $C_8$と表現します。
$\gamma_k$ を導入すると $C_8$ は次のように表現できます。

```math
N=8 \\
\gamma_k = \cos ( \frac{2 \pi k}{4 N})
```

```math
C_8 = \frac{1}{2}
\begin{bmatrix}
\gamma_4 & \gamma_4 & \gamma_4 & \gamma_4 & \gamma_4 & \gamma_4 & \gamma_4 & \gamma_4 \\
\gamma_1 & \gamma_3 & \gamma_5 & \gamma_7 & -\gamma_7 & -\gamma_5 & -\gamma_3 & -\gamma_1 \\
\gamma_2 & \gamma_6 & -\gamma_6 & -\gamma_2 & -\gamma_2 & -\gamma_6 & \gamma_6 & \gamma_2 \\
\gamma_3 & -\gamma_7 & -\gamma_1 & -\gamma_5 & \gamma_5 & \gamma_1 & \gamma_7 & -\gamma_3 \\
\gamma_4 & -\gamma_4 & -\gamma_4 & \gamma_4 & \gamma_4 & -\gamma_4 & -\gamma_4 & \gamma_4 \\
\gamma_5 & -\gamma_1 & \gamma_7 & \gamma_3 & -\gamma_3 & -\gamma_7 & \gamma_1 & \gamma_5 \\
\gamma_6 & -\gamma_2 & \gamma_2 & -\gamma_6 & -\gamma_6 & \gamma_2 & -\gamma_2 & \gamma_6 \\
\gamma_7 & -\gamma_5 & \gamma_3 & -\gamma_1 & \gamma_1 & -\gamma_3 & \gamma_5 & -\gamma_7 \\
\end{bmatrix}
```

$C_8 ^T$ を 8x8 行列 F(u,v) の 各行、各列 に 掛けることで IDCT を行います。

```math
C_8 ^T = \frac{1}{2}
\begin{bmatrix}
\gamma_4 &  \gamma_1 &  \gamma_2 &  \gamma_3 &  \gamma_4 &  \gamma_5 &  \gamma_6 &  \gamma_7 \\
\gamma_4 &  \gamma_3 &  \gamma_6 & -\gamma_7 & -\gamma_4 & -\gamma_1 & -\gamma_2 & -\gamma_5 \\
\gamma_4 &  \gamma_5 & -\gamma_6 & -\gamma_1 & -\gamma_4 &  \gamma_7 &  \gamma_2 &  \gamma_3 \\
\gamma_4 &  \gamma_7 & -\gamma_2 & -\gamma_5 &  \gamma_4 &  \gamma_3 & -\gamma_6 & -\gamma_1 \\
\gamma_4 & -\gamma_7 & -\gamma_2 &  \gamma_5 &  \gamma_4 & -\gamma_3 & -\gamma_6 &  \gamma_1 \\
\gamma_4 & -\gamma_5 & -\gamma_6 &  \gamma_1 & -\gamma_4 & -\gamma_7 &  \gamma_2 & -\gamma_3 \\
\gamma_4 & -\gamma_3 &  \gamma_6 &  \gamma_7 & -\gamma_4 &  \gamma_1 & -\gamma_2 &  \gamma_5 \\
\gamma_4 & -\gamma_1 &  \gamma_2 & -\gamma_3 &  \gamma_4 &  \gamma_5 &  \gamma_6 & -\gamma_7 \\
\end{bmatrix}
```

$C_8 ^T$ は次のように分解できます。式4とします。

```math
C_8 ^T= \frac{1}{2} A_8^T M_8^T P_8^T
```

ここでのポイントは

- 行の置換$P_8^T$
- 各列の中心から上下方向の対称性$A_8^T$

を利用して実質的には左上と右下の2つの4x4行列($M_8^T$)に変換したことです。
これにより乗算64加算56であった計算回数を乗算32加算24+8=32に減らすことができます。

$P_8^T$は置換行列です。乗算、加算は必要ありません。

```math
P_8^T  = 
\begin{bmatrix}
 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\
 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\
 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\
 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\
 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\
 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\
\end{bmatrix}
```

$M_8^T$の演算回数は乗算4x8=32 加算 3x8=24です。

```math
M_8^T  = 
\begin{bmatrix}
\gamma_4 &  \gamma_2 &  \gamma_4 &  \gamma_6 & & & & \\
\gamma_4 &  \gamma_6 & -\gamma_4 & -\gamma_2 & & & & \\
\gamma_4 & -\gamma_6 & -\gamma_4 &  \gamma_2 & & & & \\
\gamma_4 & -\gamma_2 &  \gamma_4 & -\gamma_6 & & & & \\
 & & & & \gamma_1 &  \gamma_3 &  \gamma_5 &  \gamma_7 \\
 & & & & \gamma_3 & -\gamma_7 & -\gamma_1 & -\gamma_5 \\
 & & & & \gamma_5 & -\gamma_1 &  \gamma_7 &  \gamma_3 \\
 & & & & \gamma_7 & -\gamma_5 &  \gamma_3 & -\gamma_1 \\
\end{bmatrix}
```

$A_8^T$の演算回数は加算8です。

```math
A_8^T  = 
\begin{bmatrix}
1 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 & 0 & 1 & 0 & 0 \\
0 & 0 & 1 & 0 & 0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1 & 0 & 0 & 0 & 1 \\
0 & 0 & 0 & 1 & 0 & 0 & 0 & -1 \\
0 & 0 & 1 & 0 & 0 & 0 & -1 & 0 \\
0 & 1 & 0 & 0 & 0 & -1 & 0 & 0 \\
1 & 0 & 0 & 0 & -1 & 0 & 0 & 0 \\
\end{bmatrix}
```

行については式4を適用します。演算回数は乗算8x32=256 加算 8x32=256です。
列については$M_8^T$を次のように分解した上で適用します。

```math
C_8 ^T= \frac{1}{2} A_8^T M_8^T P_8^T \\
M_8^T = F_8^T E_8^T B_8^T D_8^T \\
```

ここでのポイントは

- $D_8^T$ は各行を定数倍しているため、列ではなく行の演算時に計算できる
- 対称性とスケーリングを利用して、4つの2x2行列($B_8^T$)に変換できる

ことです。
これにより乗算32加算32であった計算回数を乗算8加算18に減らすことができます。

$P_8^T$は置換行列です。乗算、加算は必要ありません。

$D_8^T$の演算回数は乗算8ですが、あらかじめ行の$M_8^T$で計算できます。
よってここでは置換のみを行います。乗算、加算は必要ありません。

```math
D_8^T  = 
\begin{bmatrix}
\gamma_4 & 0 & 0 & 0 & & & & \\
0 & 0 & \gamma_4 & 0 & & & & \\
0 & \gamma_2 & 0 & 0 & & & & \\
0 & 0 & 0 & \gamma_2 & & & & \\
& & & & \gamma_1 & 0 & 0 & 0 \\
& & & & 0 & 0 & 0 & \gamma_1 \\
& & & & 0 & \gamma_3 & 0 & 0 \\
& & & & 0 & 0 & \gamma_3 & 0 \\
\end{bmatrix}
```

$B_8^T$の演算回数は乗算6 加算8です。

```math
B_8^T  = 
\begin{bmatrix}
1 & 1 & & & & & & \\
1 & -1 & & & & & & \\
& & 1 & \frac{\gamma_6}{\gamma_2} & & & & \\
& & \frac{\gamma_6}{\gamma_2} & -1 & & & & \\
& & & & 1 & \frac{\gamma_7}{\gamma_1} & & \\
& & & & \frac{\gamma_7}{\gamma_1} & -1 & & \\
& & & & & & 1 & \frac{\gamma_5}{\gamma_3} \\
& & & & & & \frac{\gamma_5}{\gamma_3} & -1 \\
\end{bmatrix}
```

$E_8^T$の演算回数は加算8です。

```math
E_8^T  = 
\begin{bmatrix}
1 & 0 & 1 & 0 & & & & \\
0 & 1 & 0 & 1 & & & & \\
0 & 1 & 0 & -1 & & & & \\
1 & 0 & -1 & 0 & & & & \\
& & & & 1 & 0 & 1 & 0 \\
& & & & 1 & 0 & -1 & 0 \\
& & & & 0 & 1 & 0 & 1 \\
& & & & 0 & 1 & 0 & -1 \\
\end{bmatrix}
```

$F_8^T$の演算回数は乗算2 加算2です。

```math
F_8^T  = 
\begin{bmatrix}
1 & 0 & 0 & 0 & & & & \\
0 & 1 & 0 & 0 & & & & \\
0 & 0 & 1 & 0 & & & & \\
0 & 0 & 0 & 1 & & & & \\
& & & & 1 & 0 & 0 & 0 \\
& & & & 0 & \gamma_4 & \gamma_4 & 0 \\
& & & & 0 & \gamma_4 & -\gamma_4 & 0 \\
& & & & 0 & 0 & 0 & 1 \\
\end{bmatrix}
```

$A_8^T$の演算回数は加算8です。

行の演算回数は乗算8x8=64 加算 8x26=208です。
行、列の演算回数を合計すると 乗算320 加算464 です。

## sample code
AP-922 の sample code です。
共通項にすることでMの乗算回数を減らしています。合計の乗算回数は240です。

```:makefile
CFLAGS=-I. -Wall -Werror -O2 -march=native
INCS=
OBJS=test.c
LIBS=
TARGET=test

all: $(TARGET)

%.o: %.c $(INCS)
	$(CC) $(CFLAGS) -c -o $@ $<

$(TARGET): $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^ $(LIBS)

clean:
	rm -rf $(TARGET) *.o
```

```c:test.c
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

static void IDCT(int16_t F[][8], int16_t f[][8])
{
  /*
  γk = cos(π*k/16)
  k	γ(k)
  1	0.980785280403230
  2	0.923879532511287
  3	0.831469612302545
  4	0.707106781186548
  5	0.555570233019602
  6	0.382683432365090
  7	0.195090322016128
  */
  static const double g4 = 0.707106781186548;
  static const double g[4][7] = {
    /* row 0, 4 */
    {
      0.1733799806652680, /* g1 * 0.25 * g4 */
      0.1633203706095470, /* g2 * 0.25 * g4 */
      0.1469844503024200, /* g3 * 0.25 * g4 */
      0.1250000000000000, /* g4 * 0.25 * g4 */
      0.0982118697983878, /* g5 * 0.25 * g4 */
      0.0676495125182746, /* g6 * 0.25 * g4 */
      0.0344874224103679, /* g7 * 0.25 * g4 */
    },
    /* row 1, 7 */
    {
      0.2404849415639110, /* g1 * 0.25 * g1 */
      0.2265318615882220, /* g2 * 0.25 * g1 */
      0.2038732892122290, /* g3 * 0.25 * g1 */
      0.1733799806652680, /* g4 * 0.25 * g1 */
      0.1362237766939550, /* g5 * 0.25 * g1 */
      0.0938325693794663, /* g6 * 0.25 * g1 */
      0.0478354290456362, /* g7 * 0.25 * g1 */
    },
    /* row 2, 6 */
    {
      0.2265318615882220, /* g1 * 0.25 * g2 */
      0.2133883476483180, /* g2 * 0.25 * g2 */
      0.1920444391778540, /* g3 * 0.25 * g2 */
      0.1633203706095470, /* g4 * 0.25 * g2 */
      0.1283199917898340, /* g5 * 0.25 * g2 */
      0.0883883476483185, /* g6 * 0.25 * g2 */
      0.0450599888754343, /* g7 * 0.25 * g2 */
    },
    /* row 3, 5 */
    {
      0.2038732892122290, /* g1 * 0.25 * g3 */
      0.1920444391778540, /* g2 * 0.25 * g3 */
      0.1728354290456360, /* g3 * 0.25 * g3 */
      0.1469844503024200, /* g4 * 0.25 * g3 */
      0.1154849415639110, /* g5 * 0.25 * g3 */
      0.0795474112858021, /* g6 * 0.25 * g3 */
      0.0405529186026822, /* g7 * 0.25 * g3 */
    },
  };

  static const double t[3] = {
    0.414213562373095 /* t1 = g6/g2 */,
    0.198912367379658 /* t2 = g7/g1 */,
    0.668178637919299 /* t3 = g5/g3 */,
  };

  static const int row2idx[] = {
    0, 1, 2, 3, 0, 3, 2, 1,
  };

  static double _f[8][8];

  int i;

  // row
  // add 8*(3*8+8) = 256
  // mul 8*(6+4*4) = 176
  // C = A M P
  for (i=0; i<8; i++) {
    double P[8], M[8], tmp[6];
    int idx = row2idx[i];
    /* P */
    P[0]   = F[0][i];  /* 1 0 0 0 0 0 0 0 */
    P[1]   = F[2][i];  /* 0 0 1 0 0 0 0 0 */
    P[2]   = F[4][i];  /* 0 0 0 0 1 0 0 0 */
    P[3]   = F[6][i];  /* 0 0 0 0 0 0 1 0 */
    P[4]   = F[1][i];  /* 0 1 0 0 0 0 0 0 */
    P[5]   = F[3][i];  /* 0 0 0 1 0 0 0 0 */
    P[6]   = F[5][i];  /* 0 0 0 0 0 1 0 0 */
    P[7]   = F[7][i];  /* 0 0 0 0 0 0 0 1 */
    tmp[0] = P[0] * g[idx][3];
    tmp[1] = P[1] * g[idx][1];
    tmp[2] = P[1] * g[idx][5];
    tmp[3] = P[2] * g[idx][3];
    tmp[4] = P[3] * g[idx][5];
    tmp[5] = P[3] * g[idx][1];
    /* M */
    M[0]  = tmp[0] + tmp[1] + tmp[3] + tmp[4];                                         /*  g4  g2  g4  g6  0  0  0  0 */
    M[1]  = tmp[0] + tmp[2] - tmp[3] - tmp[5];                                         /*  g4  g6 -g4 -g2  0  0  0  0 */
    M[2]  = tmp[0] - tmp[2] - tmp[3] + tmp[5];                                         /*  g4 -g6 -g4  g2  0  0  0  0 */
    M[3]  = tmp[0] - tmp[1] + tmp[3] - tmp[4];                                         /*  g4 -g2  g4 -g6  0  0  0  0 */
    M[4]  = P[4] * g[idx][0] + P[5] * g[idx][2] + P[6] * g[idx][4] + P[7] * g[idx][6]; /*  0  0  0  0  g1  g3  g5  g7 */
    M[5]  = P[4] * g[idx][2] - P[5] * g[idx][6] - P[6] * g[idx][0] - P[7] * g[idx][4]; /*  0  0  0  0  g3 -g7 -g1 -g5 */
    M[6]  = P[4] * g[idx][4] - P[5] * g[idx][0] + P[6] * g[idx][6] + P[7] * g[idx][2]; /*  0  0  0  0  g5 -g1  g7  g3 */
    M[7]  = P[4] * g[idx][6] - P[5] * g[idx][4] + P[6] * g[idx][2] - P[7] * g[idx][0]; /*  0  0  0  0  g7 -g5  g3 -g1 */
    /* A */
    _f[0][i]  = M[0] + M[4];  /*  1  0  0  0  1  0  0  0 */
    _f[1][i]  = M[1] + M[5];  /*  0  1  0  0  0  1  0  0 */
    _f[2][i]  = M[2] + M[6];  /*  0  0  1  0  0  0  1  0 */
    _f[3][i]  = M[3] + M[7];  /*  0  0  0  1  0  0  0  1 */
    _f[4][i]  = M[3] - M[7];  /*  0  0  0  1  0  0  0 -1 */
    _f[5][i]  = M[2] - M[6];  /*  0  0  1  0  0  0 -1  0 */
    _f[6][i]  = M[1] - M[5];  /*  0  1  0  0  0 -1  0  0 */
    _f[7][i]  = M[0] - M[4];  /*  1  0  0  0 -1  0  0  0 */
  }

  // column
  // add 8*26 = 208
  // mul 8*8  = 64
  // C = A F E B D P
  for (i=0; i<8; i++) {
    double P[8], D[8], B[8], E[8], _F[8];
    /* P */
    P[0]   = _f[i][0];  /* 1 0 0 0 0 0 0 0 */
    P[1]   = _f[i][2];  /* 0 0 1 0 0 0 0 0 */
    P[2]   = _f[i][4];  /* 0 0 0 0 1 0 0 0 */
    P[3]   = _f[i][6];  /* 0 0 0 0 0 0 1 0 */
    P[4]   = _f[i][1];  /* 0 1 0 0 0 0 0 0 */
    P[5]   = _f[i][3];  /* 0 0 0 1 0 0 0 0 */
    P[6]   = _f[i][5];  /* 0 0 0 0 0 1 0 0 */
    P[7]   = _f[i][7];  /* 0 0 0 0 0 0 0 1 */
    
    /* D */
    /* g4  0  0  0  0  0  0  0 */
    /*  0  0 g4  0  0  0  0  0 */
    /*  0 g2  0  0  0  0  0  0 */
    /*  0  0  0 g2  0  0  0  0 */
    /*  0  0  0  0 g1  0  0  0 */
    /*  0  0  0  0  0  0  0 g1 */
    /*  0  0  0  0  0 g3  0  0 */
    /*  0  0  0  0  0  0 g3  0 */
    D[0] = P[0];
    D[1] = P[2];
    D[2] = P[1];
    D[3] = P[3];
    D[4] = P[4];
    D[5] = P[7];
    D[6] = P[5];
    D[7] = P[6];
    
    /* B t1=g6/g2, t2=g7/g1, t3=g5/g3 */
    /*  1  1  0  0  0  0  0  0 */
    /*  1 -1  0  0  0  0  0  0 */
    /*  0  0  1 t1  0  0  0  0 */
    /*  0  0 t1 -1  0  0  0  0 */
    /*  0  0  0  0  1 t2  0  0 */
    /*  0  0  0  0 t2 -1  0  0 */
    /*  0  0  0  0  0  0  1 t3 */
    /*  0  0  0  0  0  0 t3 -1 */
    B[0] =        D[0] +        D[1];
    B[1] =        D[0] -        D[1];
    B[2] =        D[2] + t[0] * D[3];
    B[3] = t[0] * D[2] -        D[3];
    B[4] =        D[4] + t[1] * D[5];
    B[5] = t[1] * D[4] -        D[5];
    B[6] =        D[6] + t[2] * D[7];
    B[7] = t[2] * D[6] -        D[7];
    
    /* E */
    E[0] = B[0] + B[2]; /* 1  0  1  0  0  0  0  0 */
    E[1] = B[1] + B[3]; /* 0  1  0  1  0  0  0  0 */
    E[2] = B[1] - B[3]; /* 0  1  0 -1  0  0  0  0 */
    E[3] = B[0] - B[2]; /* 1  0 -1  0  0  0  0  0 */
    E[4] = B[4] + B[6]; /* 0  0  0  0  1  0  1  0 */
    E[5] = B[4] - B[6]; /* 0  0  0  0  1  0 -1  0 */
    E[6] = B[5] + B[7]; /* 0  0  0  0  0  1  0  1 */
    E[7] = B[5] - B[7]; /* 0  0  0  0  0  1  0 -1 */
    
    /* F g=g4*/
    _F[0] = E[0];               /* 1  0  0  0  0  0  0  0 */
    _F[1] = E[1];               /* 0  1  0  0  0  0  0  0 */
    _F[2] = E[2];               /* 0  0  1  0  0  0  0  0 */
    _F[3] = E[3];               /* 0  0  0  1  0  0  0  0 */
    _F[4] = E[4];               /* 0  0  0  0  1  0  0  0 */
    _F[5] = g4 * (E[5] + E[6]); /* 0  0  0  0  0  g  g  0 */
    _F[6] = g4 * (E[5] - E[6]); /* 0  0  0  0  0  g -g  0 */
    _F[7] = E[7];               /* 0  0  0  0  0  0  0  1 */
    
    /* A */
    f[i][0]  = _F[0] + _F[4];    /* 1  0  0  0  1  0  0  0 */
    f[i][1]  = _F[1] + _F[5];    /* 0  1  0  0  0  1  0  0 */
    f[i][2]  = _F[2] + _F[6];    /* 0  0  1  0  0  0  1  0 */
    f[i][3]  = _F[3] + _F[7];    /* 0  0  0  1  0  0  0  1 */
    f[i][4]  = _F[3] - _F[7];    /* 0  0  0  1  0  0  0 -1 */
    f[i][5]  = _F[2] - _F[6];    /* 0  0  1  0  0  0 -1  0 */
    f[i][6]  = _F[1] - _F[5];    /* 0  1  0  0  0 -1  0  0 */
    f[i][7]  = _F[0] - _F[4];    /* 1  0  0  0 -1  0  0  0 */
  }
}

int main(int argc, char* argv[])
{
  int i,j;
  
  int16_t F[8][8] = {
    { 568,     0,     0,    -4,    -4,     0,     4,     0 },
    { -27,     9,    -4,    -4,     0,    -5,     5,    -5 },
    { -49,    -4,     4,     4,     0,     0,     0,     0 },
    { -12,    -4,     0,     0,     5,     0,     0,     0 },
    { -14,    -5,     0,     0,     0,     0,     0,     0 },
    {  -5,     0,     0,     0,     0,     0,     0,     0 },
    {  -5,     0,     0,     0,     0,     0,     0,     0 },
    {   0,     0,     0,     0,     0,     0,     0,     1 },
  };
  /* f[8][8] after IDCT
    52   53   54   53   53   56   50   56
    67   70   71   68   65   68   62   66
    74   78   80   74   71   74   70   71
    74   78   81   78   75   77   75   76
    75   76   80   78   78   77   78   79
    75   74   76   76   75   75   77   77
    73   70   72   70   72   72   77   73
    66   65   66   63   66   69   75   69
  */
  
  int16_t f[8][8];
  
  IDCT(F, f);
  
  for (i=0; i<8; i++) {
    for (j=0; j<8; j++) {
      printf("% 4d ", f[i][j]);
    }
    printf("\n");
  }
  printf("\n");
  
  return 0;
}
```

# 演算回数
乗算、加算回数をまとめます。

| Name | Multi | Add |
|:--|:-:|:-:|
| 2D | 4096  | 4032  |
| 1D | 1024 | 896  |
| AP-922 | 320 | 464  |