2011年3月22日火曜日

[C/C++] void型とvoid型ポインタ

void型とは,型を持たない型,存在しない変数や関数,あるいは何もしない変数や関数を意味し,汎用型と呼ばれることもあります.例えば,void型関数といえば,値を返さない関数のことです.また,引数が全てvoid型の関数とは,引数がない関数のことです.

void型ポインタ(void*型)とは,どんな型へのポインタ変数にでも代入できるポインタ型です.どの型にも一致するポインタとも言えます.従って,ポインタ演算において型の不一致が起こらないので,void*型で定義された関数や変数をキャストすれば,色々な型のポインタ変数として利用することができます.ただし,void*型ポインタを格納できるだけなので,例えば

void *vp
double x = 3.14 ;
vp = &x ;

printf("The content pointed to by vp is %f. \n, *vp) ;

というような間接参照はできません.間接参照する場合は,以下のように目的の型へ変換する必要があります.

#include <stdio.h>

int main(void)
{
  double x = 3.14, *fp ;
  void *vp ;

  vp = &x ; //The void * type can assign a pointer variable to any type.
  fp = vp ;

  printf("The address of pointer variable fp is %p. \n", fp) ;
  printf("The address of pointer variable vp is %p. \n", vp) ;

  printf("The address of pointer variable fp is %f. \n", *fp) ;

  //Cast is necessary for indirect reference.
  printf("The address of pointer variable vp is %f. \n", *(double *)vp) ;

  return 0 ;

}





2011年3月21日月曜日

[C/C++] キャスト

配列でデータ領域を確保すると,それが不要になったときも,プログラムが終了するまで,その配列がメモリを占有してしまうので,配列に占有された部分が無駄になります.
そこで,記憶領域を効率よく利用するために,必要なときに記憶領域を確保し,不要になったらそれを開放する機能を動的メモリ確保(Dynamic memory allocation)としいます.
そして,記憶領域を確保することをアロケートといい,それを実現するために使用される関数をアロケート関数といいます.また,動的に確保した領域を解放するための関数がfree関数です.アロケート関数を利用するには"stdlib.h"が必要です.

malloc関数の返す型は,voidへのポインタ型,つまり,void*となっています.
この意味を理解するためにはvoid型ポインタの考えを知っておく必要があります.
また,malloc関数を使うにはキャストという考え方も知る必要があります.

キャストとは,変数や式といったオペラントの型を一時的に変更することです.
キャストを行うにはキャスト演算子を使用します.
これは,データの型変換を行う演算子で,明示的に型変換を行いたい場合に使用します.
例えば,int型の変数 i, j をdouble型へ変換したい場合には,

int i, j ;
(double)i ;
(double) i+j ;

とします.
この(double0 の部分がキャスト演算子です.
逆にdouble型の変数aをint型へ変換したいときには(int)aとします.

ただし,int型へのポインタ変数iをdouble型へのポインタ変数に変換しようとして

#include <stdio.h>

int main(void)
{
  int *i ;
  (double *)i = 1.0 / 2.0 ;

  return 0 ;
}

とするとエラーになります.
なお,文法上は以下のようにして変数を用意してポインタ変数のキャストが可能です.

#include <stdio.h>

int main(void)
{
  int *i ;
  double a ;

  i = (int *)&a ; //

  return 0 ;
}

しかし,このようなポインタのキャストはプログラムが読みにくくなるので,止めた方が良いとされています.

2011年3月14日月曜日

[C/C++] プログラムの実行時間の計測

プログラムの実行時間を測るにはclock関数を使います.このclock関数を使うには time.hが必要です.この関数を使ってプログラムの実行時間を計測するには,計測したい部分の始めとと終わりにclock関数を記述してその差を取ります.

clock関数は返り値としてclock_t型を返します.多くの場合は,clock.t型はlong型と同じです.以下に実行時間を測るためのプログラム例を示します.

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

#define N 10000000

int main(void)
{
  clock_t t ;
  double a ;
  long i ;

  t = clock() ;                     //Start measurement

  for( i = 1 ; i <= N ; i++)
  {
    sin(30.0) * cos(20.0) * tan(15.0) + sin(30.0) + cos(20.0) + tan(15.0) ;
  }

  t = clock() - t ;                 //Acquire execution time
  a = (double)t / CLOCKS_PER_SEC ;  //Convert execution time to seconds

  printf("Execution time is %f seconds (%ld μ s)\n", a, t) ;

  return 0 ;
}

上記のプログラムで"(double)"は計算結果をdouble型にするための命令です.また,clock関数で得られた値を秒単位に変換するには値をCLOCKS_PER_SECで割ります.上記のプログラムをコンパイル,実行すると以下のようになります.
Execution time is 0.034697 seconds (34697 μ s)

2011年3月1日火曜日

[C/C++] ホイン法

ホイン法は常微分方程式
        y' = f(x, y)        (1)
        y(a) = y0           (2)
を満たすy(x)の近似値を求めるための方法です.ここで,a, y0は与えられた定数,f(x, y)は与えられた関数です.今,上記の2式を閉区間[a, b]上で与え,区間[a, b]をn等分して,各点xiを
        h = (b-a)/n,    x0 = a,     xi = a + ih    (i = 0, 1, 2, ..., n)
とします.なお,nを分割数,hを刻み幅と呼びます.

式(1)より
  (3)
となります.ここで,2変数のテイラー展開より
       
(4)
が成り立つので,yi = f(xi) とし,式(4)において,α=1, β=f(xi, yi)として式(3)を適用すれば

(5)
となります.ただし,O(h^n)はランダウの記号で,今の場合は最低次数がnであるhの多項式です.

一方,yi = f(xi)とするとテイラー展開より
となるので,これと式(5)より
となります.この式において,hは十分に小さいとしてO(h^3)を無視して,Yi = yi,つまり,xi上のy(x)の近似値をYiとすれば,ホイン法
が得られます.

ホイン法のアルゴリズムは以下のようになります.

以下に,ホイン法で常微分方程式
        y' = x + y,        0<= x <= 1,        y(0) = 1
を解くプログラム例を示します.

#include <stdio.h>

double f(double x, double y) ;

int main(void)
{
  double x = 0.0, y = 1.0, b = 1.0, h, k1, k2 ;
  int i, n ;

  printf("Input the number of partitions. ---> ") ;
  scanf("%d", &n) ;
  h = (b - x) / n ;

  for (i = 0 ; i < n ; i++)
  {
    k1 = f(x, y) ; k2 = f(x + h, y + h * k1) ;
    y = y + h / 2.0 * (k1 + k2) ;
    x += h ;
    printf("x = %f \t y = %f \n", x, y) ;
  }
  return 0 ;
}

double f(double x, double y)
{
  return(x + y) ;
}

Input the number of partitions. ---> 10
x = 0.100000  y = 1.110000 
x = 0.200000  y = 1.242050 
x = 0.300000  y = 1.398465 
x = 0.400000  y = 1.581804 
x = 0.500000  y = 1.794894 
x = 0.600000  y = 2.040857 
x = 0.700000  y = 2.323147 
x = 0.800000  y = 2.645578 
x = 0.900000  y = 3.012364 
x = 1.000000  y = 3.428162