2009年8月29日土曜日

ベクトルの内積 (Inner product)

公式



C言語での実装

#include <stdio.h>

/* ---------------------------------------------
  ベクトルの内積を求める
  引数1: vec1 ベクトル1
  引数2: vec2 ベクトル2
  引数3: n ベクトルの要素数
  戻り値 ベクトルの内積
 ---------------------------------------------*/
double inner_product(double *vec1, double *vec2, int n) {
    int i;
    double s = 0.0;

    for ( i = 0; i < n; i++ ) {
        s += vec1[i] * vec2[i];
    }

    return s;
}

/* main */
int main(void)
{
    double a[] = {1.0, 2.0, 3.0};
    double b[] = {2.0, 3.0, 4.0};
    int n = 3;

    /* ベクトルの内積を求める */
    printf("内積: %.2f\n", inner_product(a, b, n));

    return 0;
}
実行例
内積: 20.00

2009年8月27日木曜日

ベクトルの長さ

公式



C言語での実装

#include <stdio.h>
#include <math.h>

/* ---------------------------------------------
  ベクトルの長さを求める
  引数1: vec ベクトル
  引数4: n ベクトルの要素数
  戻り値 vecの長さ
 ---------------------------------------------*/
double norm(double *vec, int n)
{
    int i;
    double s = 0.0;

    for ( i = 0; i < n; i++ ) {
        s += vec[i] * vec[i];
    }

    return sqrt(s);
}

/* main */
int main(void)
{
    double vec[] = {1.0, 2.0, 3.0};
    int n = 3;

    /* ベクトルの長さを求める */
    printf("ベクトルの長さ: %f\n", norm(vec, n));

    return 0;
}
実行例
ベクトルの長さ: 3.741657

2009年8月25日火曜日

ベクトルの差

公式



C言語での実装

#include <stdio.h>

/* ---------------------------------------------
  ベクトルの和を計算する
  引数1: vec1 ベクトル1
  引数2: vec2 ベクトル2
  引数3: sum ベクトルの和
  引数4: n ベクトルの要素数
  戻り値 sumの先頭アドレス
 ---------------------------------------------*/
double *diff_vector(double *vec1,
        double *vec2, double *diff, int n)
{
    while (n--)
        diff[n] = vec1[n] - vec2[n];
    return diff;
}

/* main */
int main(void)
{
    double vec1[] = {1.0, 2.0, 3.0};
    double vec2[] = {2.0, 4.0, 1.0};
    double diff[3];
    int i, n = 3;

    /* ベクトルの差を計算 */
    diff_vector(vec1, vec2, diff, n);

    for ( i = 0; i < n; i++ ) {
        printf("diff[%d] = %.2f\n", i, diff[i]);
    }

    return 0;
}
実行例
diff[0] = -1.00
diff[1] = -2.00
diff[2] = 2.00

2009年8月23日日曜日

ベクトルの和

公式



C言語での実装

#include <stdio.h>

/* ---------------------------------------------
  ベクトルの和を計算する
  引数1: vec1 ベクトル1
  引数2: vec2 ベクトル2
  引数3: sum ベクトルの和
  引数4: n ベクトルの要素数
  戻り値 sumの先頭アドレス
 ---------------------------------------------*/
double *sum_vector(double *vec1,
        double *vec2, double *sum, int n)
{
    while (n--)
        sum[n] = vec1[n] + vec2[n];
    return sum;
}

/* main */
int main(void)
{
    double vec1[] = {1.0, 2.0, 3.0};
    double vec2[] = {2.0, 4.0, 1.0};
    double sum[3];
    int i, n = 3;

    /* ベクトルの和を計算 */
    sum_vector(vec1, vec2, sum, n);

    for ( i = 0; i < n; i++ ) {
        printf("sum[%d] = %.2f\n", i, sum[i]);
    }

    return 0;
}
実行例
sum[0] = 3.00
sum[1] = 6.00
sum[2] = 4.00

2009年8月9日日曜日

三角形の重心(Triangle’s center of gravity)

公式

A(x1, y1),B(x2, y2),C(x3, y3)のとき△ABCの重心Gの座標は

C言語での実装

#include <stdio.h>
#include <math.h>

/* ---------------------------------------------
   3点A,B,Cからなる三角形の重心を求める (2次元)
   引数1: A 点の座標1
   引数2: B 点の座標2
   引数3: C 点の座標3
   引数5: G 重心
   戻り値: 重心の先頭アドレス
 ---------------------------------------------*/
double *triangle_center_of_gravity(double A[2],
        double B[2], double C[2], double G[2])
{
    G[0] = (A[0] + B[0] + C[0]) / 3.0;
    G[1] = (A[1] + B[1] + C[1]) / 3.0;
    return G;
}

/* main */
int main(void)
{
    double A[] = {0.0, 1.0};
    double B[] = {-1.0, 0.0};
    double C[] = {1.0, 0.0};
    double G[2];

    triangle_center_of_gravity(A, B, C, G);
    printf("3点A,B,Cからなる三角形の重心G(%.2f, %.2f)\n",
        G[0], G[1]);

    return 0;
}
実行例
3点A,B,Cからなる三角形の重心G(0.00, 0.33)

2009年8月8日土曜日

外分点(externally dividing point)

公式

2点 P(x1, y1),Q(x2, y2)について、線分PQをm:nに外分する点Rは

C言語での実装

#include <stdio.h>
#include <math.h>

/* ---------------------------------------------
   2点p1,p2からなる線分をm:nに外分する点を求める (2次元)
   引数1: P 点の座標1
   引数2: Q 点の座標2
   引数3: m m:nのm
   引数4: n m:nのn
   引数5: result 外分点
   戻り値: 1 正常終了,0 異常終了
 ---------------------------------------------*/
int divide_externally_2D(double P[2],
        double Q[2], int m, int n, double R[2])
{
    if (m - n == 0) return 0;

    R[0] = (-n * P[0] + m * Q[0]) / (m - n);
    R[1] = (-n * P[1] + m * Q[1]) / (m - n);

    return 1;
}

/* main */
int main(void)
{
    double P[] = {1.0, 3.0};
    double Q[] = {2.0, 4.0};
    double R[2];
    int m = 2;
    int n = 3;

    divide_externally_2D(P, Q, m, n, R);
    printf("線分PQを%d:%dに外分する点R(%.2f, %.2f)\n", 
        m, n, R[0], R[1]);

    return 0;
}
実行例
2点P,Qからなる線分を2:3に外分する点R(-1.00, 1.00)

2009年8月7日金曜日

内分点 (internally dividing point)

公式

2点 P(x1, y1),Q(x2, y2)について、線分PQをm:nに内分する点Rは

C言語での実装

#include <stdio.h>
#include <math.h>
/* ---------------------------------------------
   2点P,Qからなる線分をm:nに内分する点を求める (2次元)
   引数1: P 点の座標1
   引数2: Q 点の座標2
   引数3: m m:nのm
   引数4: n m:nのn
   引数5: result 内分点
   戻り値: 1 正常終了,0 異常終了
 ---------------------------------------------*/
int divide_internally_2D(double P[2], 
        double Q[2], int m, int n, double R[2])
{
    if (m < 1 && n < 1) return 0;

    R[0] = (n * P[0] + m * Q[0]) / (m + n);
    R[1] = (n * P[1] + m * Q[1]) / (m + n);

    return 1;
}

/* main */
int main(void)
{
    double P[] = {1.0, 3.0};
    double Q[] = {2.0, 4.0};
    double R[2];
    int m = 2;
    int n = 3;

    divide_internally_2D(P, Q, m, n, R);
    printf("線分PQを%d:%dに内分する点R(%.2f, %.2f)\n", 
        m, n, R[0], R[1]);

    return 0;
}
実行例
線分PQをを2:3に内分する点R(1.40, 3.40)

2009年8月5日水曜日

2点間の距離 (Euclidean distance)

公式

2点 P(x1, y1),Q(x2, y2)のとき

C言語での実装

#include <stdio.h>
#include <math.h>

/* ---------------------------------------------
  2点間の距離を求める
  引数1: p1 点の座標1
  引数2: p2 点の座標2
  引数3: n 次元数
  戻り値 p1とp2間の距離
 ---------------------------------------------*/
double distance(double *p1, double *p2, int n)
{
    int i;
    double distance = 0.0;

    for (i = 0; i < n; i++) {
        distance += (p2[i] - p1[i]) * (p2[i] - p1[i]);
    }
    return sqrt(distance);
}

/* main */
int main(void)
{
    double p1[] = {1.0, 2.0, 3.0};
    double p2[] = {1.0, 2.0, 4.0};
    double d;

    d = distance(p1, p2, 3);
    printf("2点間の距離:%f\n", d);

    return 0;
}
実行例
2点間の距離:1.000000

2009年8月4日火曜日

共分散 (covariance)

公式

C言語での実装

式(3) を実装。ゼロ除算を防ぐために、nが0(0以下)の場合は0を返すようにする。
#include <stdio.h>
#include <math.h>

/* ---------------------------------------------
  共分散を計算する
  引数1: x データ1
  引数2: y データ2
  引数3: n xとyの要素数
  戻り値 共分散
 ---------------------------------------------*/
double covariance(double *x, double *y, int n)
{
    int i;
    double sum_x = 0.0, sum_y = 0.0;
    double avg_x, avg_y;
    double sumprod = 0.0;

    if ( n < 1 ) return 0.0;

    for (i = 0; i < n; i++) {
        sum_x += x[i]; /* xの和 */
        sum_y += y[i]; /* yの和 */
        sumprod += x[i] * y[i];
    }

    avg_x = sum_x / (double)n; /* xの平均 */
    avg_y = sum_y / (double)n; /* yの平均 */
    return sumprod / (double)n - avg_x * avg_y; /* 共分散 */
}


/* main */
int main(void)
{
    double x[] = {1.0, 2.0, 3.0};
    double y[] = {1.0, 2.0, 3.0};
    double cov;

    cov = covariance(x, y, 3);
    printf("共分散:%f\n", cov);

    return 0;
}
実行例
共分散:0.666667

2009年8月3日月曜日

不偏分散 (unbiased variance)

公式

C言語での実装

式(2) を実装。ほぼ分散と同じ。 ゼロ除算を防ぐために、nが2未満の場合は0を返すようにする。
#include <stdio.h>
#include <math.h>

/* ---------------------------------------------
  不偏分散を計算する
  引数1: a データ
  引数2: n aの要素数
  戻り値 不偏分散
 ---------------------------------------------*/
double unbiased_variance(double *a, int n)
{
    int i;
    double sum = 0.0;
    double sqsum = 0.0;
    double avg;

    if ( n < 2 ) return 0.0;

    for (i = 0; i < n; i++) {
        sum += a[i]; /* 和 */
        sqsum += a[i] * a[i]; /* 平方和 */
    }

    avg = sum / (double)n; /* 平均 */
    return sqsum / (double)(n - 1) - avg * avg; /* 不偏分散 */
}

/* main */
int main(void)
{
    double numbers[] = {1.0, 2.0, 3.0};
    double u;

    u = unbiased_variance(numbers, 3);
    printf("不偏分散:%f\n", u);

    return 0;
}
実行例
不偏分散:0.3000000

2009年8月2日日曜日

組み合わせ (combination)

公式

異なるn個のものから異なるr個のものを選ぶ組み合わせの数は

今回は式(2)を実装。階乗 (factoral) で実装したfactorial関数を利用する。

C言語での実装

#include <stdio.h>

/* ---------------------------------------------
  階乗を計算する
  引数1: n 整数
  戻り値 階乗
 ---------------------------------------------*/
int factorial(int n)
{
    int fact = n;

    if (n <= 0) return 1;

    while (--n)
        fact *= n;

    return fact;
}

/* ---------------------------------------------
  組み合わせの総数を計算する
  引数1: n nCrのn
  引数2: r nCrのr
  戻り値 組み合わせの総数
 ---------------------------------------------*/
int combination(int n, int r)
{
    if (r <= 0) return 1;
    return factorial(n) / (factorial(r) * factorial(n - r));
}

/* main */
int main(void)
{
    int n = 5;
    int r = 3;
    int c;

    c = combination(n, r);
    printf("%dC%d = %d\n", n, r, c);

    return 0;
}
実行例
5C3 = 10

2009年8月1日土曜日

順列 (permutation)

公式

異なるn個のものからr個とって1列に並べる順列の数は

今回は式(2)を実装。階乗 (factoral) で実装したfactorial関数を利用する。

C言語での実装

#include <stdio.h>

/* ---------------------------------------------
  階乗を計算する
  引数1: n 整数
  戻り値 階乗
 ---------------------------------------------*/
int factorial(int n)
{
    int fact = n;

    if (n <= 0) return 1;

    while (--n)
        fact *= n;

    return fact;
}


/* ---------------------------------------------
  順列組み合わせの総数を計算する
  引数1: n nPrのn
  引数2: r nPrのr
  戻り値 順列組み合わせの総数
 ---------------------------------------------*/
int permutation(int n, int r)
{
    if (r <= 0) return 1;
    return factorial(n) / factorial(n - r);
}

/* main */
int main(void)
{
    int n = 5;
    int r = 3;
    int p;

    p = permutation(n, r);
    printf("%dP%d = %d\n", n, r, p);

    return 0;
}
実行例
5P3 = 60

2009年7月31日金曜日

階乗 (factorial)

公式


階乗は再帰呼び出しの例としてよく扱われる。 今回は非再帰版と再帰版の両方を実装。

C言語での実装

#include <stdio.h>

/* ---------------------------------------------
  階乗を計算する
  引数1: n 整数
  戻り値 階乗
 ---------------------------------------------*/
int factorial(int n)
{
    int fact = n;

    if (n <= 0) return 1;

    while (--n)
        fact *= n;

    return fact;
}


/* ---------------------------------------------
  階乗を計算する (再帰)
  引数1: n 整数
  戻り値 階乗
 ---------------------------------------------*/
int factorial_recursive(int n)
{
    if ( n <= 0 ) {
        return 1;
    } else {
        return factorial_recursive(n - 1) * n;
    }
}

/* main */
int main(void)
{
    int n = 5;
    int fact;

    fact = factorial(n);
    printf("%d! = %d\n", n, fact);

    fact = factorial_recursive(n);
    printf("%d! = %d\n", n, fact);

    return 0;
}
実行例
5! = 120
5! = 120

2009年7月29日水曜日

最大値 (maximum)と最小値 (minimum)

C言語での実装

#include <stdio.h>

/* ---------------------------------------------
  最大値を求める
  引数1: a 入力配列
  引数2: n 配列の要素数
  戻り値 最大値
 ---------------------------------------------*/
double max(const double *a, int n)
{
    int i;
    double max;

    if ( n < 1 ) return 0.0;

    max = a[0];
    for (i = 1; i < n; i++) {
        if ( max < a[i] ) max = a[i];
    }

    return max;
}


/* ---------------------------------------------
  最小値を求める
  引数1: a 入力配列
  引数2: n 配列の要素数
  戻り値 最小値
 ---------------------------------------------*/
double min(const double *a, int n)
{
    int i;
    double min;

    if ( n < 1 ) return 0.0;

    min = a[0];
    for (i = 1; i < n; i++) {
        if ( min > a[i] ) min = a[i];
    }

    return min;
}

/* main */
int main(void)
{
    double numbers[] = {1.0, 2.0, 3.0};
    double max_val, min_val;

    max_val = max(numbers, 3);
    min_val = min(numbers, 3);
    printf("最大値:%f\n", max_val);
    printf("最小値:%f\n", min_val);

    return 0;
}
実行例
最大値:3.000000
最小値:1.000000

2009年7月28日火曜日

分散 (標本分散: sample variance) と 標準偏差 (standard deviation)

分散はデータのバラツキ。
平均からどれくらいサンプルが離れているかを知りたいので、 平均からサンプルを引き、負の値にしないために2乗すると考えると分かりやすい。
標準偏差は分散の平方根。

公式 (分散)


公式 (標準偏差)


C言語での実装

式(2) を実装。ゼロ除算を防ぐために、nが0(0以下)の場合は0を返すようにする。
#include <stdio.h>
#include <math.h>

/* ---------------------------------------------
  分散を計算する
  引数1: a データ
  引数2: n aの要素数
  戻り値 分散
 ---------------------------------------------*/
double variance(double *a, int n)
{
    size_t i;
    double sum = 0.0;
    double sqsum = 0.0;
    double avg;

    if ( n < 1 ) return 0.0;

    for (i = 0; i < n; i++) {
        sum += a[i]; /* 和 */
        sqsum += a[i] * a[i]; /* 平方和 */
    }

    avg = sum / (double)n; /* 平均 */
    return sqsum / (double)n - avg * avg; /* 分散 */
}

/* main */
int main(void)
{
    double numbers[] = {1.0, 2.0, 3.0};
    double var, std_dev;

    var = variance(numbers, 3);
    std_dev = sqrt(var);
    printf("分散:%f\n", var);
    printf("標準偏差:%f\n", std_dev);

    return 0;
}
実行例
分散:0.666667
標準偏差:0.816497

2009年7月26日日曜日

シグモイド関数 (sigmoid function)

階段関数(step function)は微分不可能な点がある。 パーセプトロンのBP法などでは、傾きを求めるために微分する必要があるので、階段関数の代わりにシグモイド関数が使用される。

シグモイド関数


C言語での実装

#include <stdio.h>
#include <math.h>

/* ---------------------------------------------
  シグモイド関数を計算する
  引数1: x
  引数2: gain ゲイン
  戻り値 シグモイド関数
 ---------------------------------------------*/
double sigmoid(double x, double gain)
{
  return 1.0 / (1.0 + exp(-gain * x));
}

/* main */
int main(void)
{
    double sig;
    double x = -6.0;
    double step = 0.01;

    while ( x < 6.0 + step ) {
        sig = sigmoid(x, 1.0);
        printf("%.5f\t%.16f\n", x, sig);
        x += step;
    }

    return 0;
}
実行例
gnuplotを使用して出力結果をプロットすると以下のように表示される。

平均 (average)

公式



C言語での実装


合計(総和)を求め、データ数で除算すればよい。
#include <stdio.h>

/* ---------------------------------------------
  平均を計算する
  引数1: a データ
  引数2: n aの要素数
  戻り値 平均
 ---------------------------------------------*/
double average(double *a, int n)
{
    int i;
    double sum = 0;

    for ( i = 0; i < n; i++ ) {
        sum += a[i];
    }

    return sum / n;
}

/* main */
int main(void)
{
    double numbers[] = {1.0, 2.0, 3.0};
    double sum;

    sum = average(numbers, 3);
    printf("平均:%f\n", sum);

    return 0;
}
実行例
平均:2.000000

積和 (sum of products)

公式



C言語での実装

#include <stdio.h>

/* ---------------------------------------------
  積和を計算する
  引数1: a1 データ1
  引数2: a2 データ2
  引数3: n a1とa2の要素数
  戻り値 積和
 ---------------------------------------------*/
double sum_of_products(double *a1, double *a2, int n)
{
    double sum = 0;

    while (n) {
        n--;
        sum += (a1[n] * a2[n]);
    }

    return sum;
}

/* main */
int main(void)
{
    double data1[] = {1.0, 2.0, 3.0};
    double data2[] = {2.0, 3.0, 4.0};
    double sum;

    sum = sum_of_products(data1, data2, 3);
    printf("積和:%f\n", sum);

    return 0;
}
実行例
積和:20.000000

平方和 (sum of squares)

ここでの平方和は、いわゆる偏差平方和ではないので注意!

公式



C言語での実装

#include <stdio.h>

/* ---------------------------------------------
  平方和を計算する
  引数1: a データ
  引数2: n 配列の要素数
  戻り値 平方和
 ---------------------------------------------*/
double sum_of_squares(double *a, int n)
{
    double sum = 0;

    while (n--) {
        sum += (a[n] * a[n]);
    }

    return sum;
}

/* main */
int main(void)
{
    double numbers[] = {1.0, 2.0, 3.0};
    double sum;

    sum = sum_of_squares(numbers, 3);
    printf("平方和:%f\n", sum);

    return 0;
}
実行例
平方和:14.000000

総和 (summation)

公式



C言語での実装

#include <stdio.h>

/* ---------------------------------------------
  総和を計算する
  引数1: a データ
  引数2: n aの要素数
  戻り値 総和
 ---------------------------------------------*/
double summation(double *a, int n)
{
    double sum = 0;

    while (n--)
        sum += a[n];

    return sum;
}

/* main */
int main(void)
{
    double numbers[] = {1.0, 2.0, 3.0, 4.0, 5.0};
    double sum;

    sum = summation(numbers, 5);
    printf("総和:%f\n", sum);

    return 0;
}