プログラミングなどなど

プログラミングに関係しそうな内容を

C言語:積を計算する関数も定義してみる

階乗を計算する関数

和に引き続き積についても同じように関数を定義したいと思います。まずは、階乗を求める関数から定義してみます。

ソースは前回からの続きとなっています。

factorial01.c
#include "util.h"

int factorial(int n)
{
	int acc = 1;

	int i;
	for (i = 1; i <= n; i++) {
		acc *= id(i);
	}
	return acc;
}
util.h
#ifndef __UTIL_H__
#define __UTIL_H__

int sumId(int);
int sumSquare(int);
int factorial(int);

int sumf(int, int (*)(int));

int id(int);
int square(int);

#endif
main.c
#include <stdio.h>
#include "util.h"

int main(void)
{
	int n = 10;
	printf("sumId : %d %d\n", n, sumId(n));
	printf("sumSquare : %d %d\n", n, sumSquare(n));
	printf("factorial : %d %d\n", n, factorial(n));

	printf("sumf id : %d %d\n", n, sumf(n, id));
	printf("sumf square : %d %d\n", n, sumf(n, square));

	return 0;
}
コンパイルと実行
$ gcc -Wall sumId02.c sumSquare02.c factorial01.c sumf.c util.c main03.c
$ ./a.out
sumId : 10 55
sumSquare : 10 385
factorial : 10 3628800
sumf id : 10 55
sumf square : 10 385
sumIdとfactorialの比較
$ sdiff -t sumId02.c factorial01.c
#include "util.h"                                  #include "util.h"

int sumId(int n)                                |  int factorial(int n)
{                                                  {
        int acc = 0;                            |          int acc = 1;

        int i;                                             int i;
        for (i = 1; i <= n; i++) {                         for (i = 1; i <= n; i++) {
                acc += id(i);                   |                  acc *= id(i);
        }                                                  }
        return acc;                                        return acc;
}                                                  }

着目すべき違いは初期値、複合代入演算子の部分となります。
複合代入演算子の部分をもう少し愚直に書いてみると次のようになります。

和と積の差分(複合演算子の展開)

sumId03.c
#include "util.h"

int sumId(int n)
{
	int acc = 0;

	int i;
	for (i = 1; i <= n; i++) {
		acc = acc + id(i);
	}
	return acc;
}
factorial02.c
#include "util.h"

int factorial(int n)
{
	int acc = 1;

	int i;
	for (i = 1; i <= n; i++) {
		acc = acc * id(i);
	}
	return acc;
}
コンパイルと実行
$ gcc -Wall sumId03.c sumSquare02.c factorial02.c sumf.c util.c main03.c
$ ./a.out
sumId : 10 55
sumSquare : 10 385
factorial : 10 3628800
sumf id : 10 55
sumf square : 10 385

sumIdとfactorialの比較(複合演算子展開)

$ sdiff -t sumId03.c factorial02.c
#include "util.h"                                  #include "util.h"

int sumId(int n)                                |  int factorial(int n)
{                                                  {
        int acc = 0;                            |          int acc = 1;

        int i;                                             int i;
        for (i = 1; i <= n; i++) {                         for (i = 1; i <= n; i++) {
                acc = acc + id(i);              |                  acc = acc * id(i);
        }                                                  }
        return acc;                                        return acc;
}                                                  }

両者の違いは acc = acc + id(i) と acc = acc * id(i) の部分になります。
つまり、accに和の結果を入れるか、積の結果を入れるかです。

和も積も2引数を取る関数として書くことができるので、和の時と同じようにもう少し前準備して見やすくします。

和と積部分の関数化

sumId04.c
#include "util.h"

int sumId(int n)
{
	int acc = 0;

	int i;
	for (i = 1; i <= n; i++) {
		acc = add(acc, id(i));
	}
	return acc;
}
factorial03.c
#include "util.h"

int factorial(int n)
{
	int acc = 1;

	int i;
	for (i = 1; i <= n; i++) {
		acc = mul(acc, id(i));
	}
	return acc;
}
util.h
#ifndef __UTIL_H__
#define __UTIL_H__

int sumId(int);
int sumSquare(int);
int factorial(int);

int sumf(int, int (*)(int));

int id(int);
int square(int);
int add(int, int);
int mul(int, int);

#endif
util.c
#include "util.h"

int id(int x) { return x; }
int square(int x) { return x * x; }

int add(int x, int y) { return x + y; }
int mul(int x, int y) { return x * y; }
sumIdとfactorialの比較(和と積の関数化)
$ sdiff -t sumId04.c factorial03.c
#include "util.h"                                   #nclude "util.h"

int sumId(int n)                                 |  it factorial(int n)
{                                                   {
        int acc = 0;                             |         int acc = 1;

        int i;                                             int i;
        for (i = 1; i <= n; i++) {                         for (i = 1; i <= n; i++) {
                acc = add(acc, id(i));           |                 acc = mul(acc, id(i));
        }                                                  }
        return acc;                                        return acc;
}                                                   }

着目する違いはaddとmulです。
後はaccの初期値を引数としてもらうことにします。
これらを加味して関数を書くと次のようになります。

和と積を引数でとる

和と積の関数を引数で取れるようにして、どのように集めるかを調整可能にします。

acc.c
#include "util.h"

int acc(int n, int init, int (*con)(int,int), int (*f)(int))
{
	int acc = init;

	int i;
	for (i = 1; i <= n; i++) {
		acc = con(acc, f(i));
	}
	return acc;
}
util.h
#ifndef __UTIL_H__
#define __UTIL_H__

int sumId(int);
int sumSquare(int);
int factorial(int);

int sumf(int, int (*)(int));
int acc(int, int, int (*)(int,int), int (*)(int));

int id(int);
int square(int);
int add(int, int);
int mul(int, int);

#endif
main.c
#include <stdio.h>
#include "util.h"

int main(void)
{
	int n = 10;
	printf("sumId : %d %d\n", n, sumId(n));
	printf("sumSquare : %d %d\n", n, sumSquare(n));
	printf("factorial : %d %d\n", n, factorial(n));

	printf("sumf id : %d %d\n", n, sumf(n, id));
	printf("sumf square : %d %d\n", n, sumf(n, square));

	printf("acc 0 add id : %d %d\n", n, acc(n, 0, add, id));
	printf("acc 0 add square : %d %d\n", n, acc(n, 0, add, square));
	printf("acc 1 mul id : %d %d\n", n, acc(n, 1, mul, id));

	return 0;
}
コンパイルと実行
$ gcc -Wall sumId04.c sumSquare02.c factorial03.c sumf.c acc.c util.c main04.c
$ ./a.out</kbd>
sumId : 10 55
sumSquare : 10 385
factorial : 10 3628800
sumf id : 10 55
sumf square : 10 385
acc 0 add id : 10 55
acc 0 add square : 10 385
acc 1 mul id : 10 3628800

accを使うと、どのように結果をまとめていくかも制御できます。