Sponsored Link
 
>>  Main > Programing > Primary > 0007

D言語入門 第07章 - 関数1

#01 - 関数とは

数学の関数について

今回は関数というものについて説明します。 まぁ、今回も変数の時と同様、大して楽しくもないので、
数学の関数については周知だ、な人はこちら
ご託はいい、とりあえずコード晒せ、な人はこちら
へどうぞ。


――さて、関数は、数学などでおなじみの、機能を持った数のことです。
Wikipediaや辞書をみると、とある変数を入力してやることで、その変数に対応した値が従属的に定まる対応関係と表現されているようです。
たとえば中学校の2年生で習う一次関数では、ある数xに対応したyがありますね。
y = 3x + 5
この式では、xに0を代入するとyは5に、xに1を代入するとyは8に、xに2を代入するとyは11になりますね。

x...-3-2-10123... y...-4-12581114...

このような関数の書き方は、数学では高校生で習う範囲では、
f(x) = 3x + 5
と書くことがありますね。
f(1)とすると、この値は8になるわけです。

円の面積を求めるような関数を考えるとこのようになります。
A(r) = πr2
この関数を利用すると、次のようなことができます。

例題)半径10mの赤く塗られた円があります。その赤い円の中には半径1mの小さな青く塗られた円が4個あります。赤い部分の面積は何平方メートルでしょうか。
この例題の赤い部分の面積は、先のA(r)の関数を使って、このように表すことができます。
A(10) - 4×A(1)
半径10の円の面積から、半径1の円の面積×4つ分を引くわけですね。

数学で関数と言って、特に有名なものは、たとえば三角関数がありますね。
sin(x) = x -(x3/3!) +(x5/5!) -(x7/7!) .......
cos(x) = 1 -(x2/2!) +(x4/4!) -(x6/6!) .......
tan(x) = sin(x) / cos(x)
(sinやcosの右辺は、テイラー展開されたもの)
先ほどのA(r)などのように、自分で定義したような関数もあれば、正弦関数や余弦関数などのように、有名な人が定義してそのまま常識になってしまったような関数もあります。 関数の利点としては、正弦関数のような、中身が非常に複雑なものでも、内容はブラックボックスとして、適当な入力を与えるとそれに対応した値が返ってくるという事実だけを見て、利用することができるという点が挙げられます。
また、先ほどの三角関数のように、複雑なものを一つにまとめることで記述を簡略化することもできたりもします。

このような使い方ができるもの、それが関数というものです。
詳しくはWikipediaやGoogle大先生に頼るなり、中学高校の数学の教科書などを見るなどしましょう。

今回のミソ

  • 関数とは、機能を持った数
  • 関数に与えた値と返ってくる値はそれぞれ対応している
  • 数学での関数の定義は f(x) = 3x + 5 のように書く
  • sin(x)やcos(x)などの有名なものもある
  • 関数の中身はブラックボックスとして扱うことができる
  • 関数を使うと簡単に書ける場合がある。

#02 - プログラミングでの関数

プログラミングの関数について

さて、その関数ですが、D言語にも関数というものがあります。
D言語といわず、プログラミング言語では、ある作業をひとまとめにして、一つの手続きにしたものという意味合いが強いです。
数学の、簡単に書ける場合があるっていうそれですね。
プログラミングにおいての関数の呼び方としては、サブルーチンや、メソッドということもあります。

プログラミングで関数とはどういうことかというと、たとえば、前回までに使ってきた writef というもの。
これは、入力されたものを、文字列に直して表示させるというものでしたが、この中では、

  • 文法の解釈
  • 入力されたものを文字列に変換する
  • 整形する
  • コンソールに出力する

というような一連の処理を行って文字を表示しています(いるのだと思います)。
これらの処理を writef という「関数」にまとめて一つの手続きにしてあるので、このような一連の処理を writef という関数に任せることができるわけです。

ところで、数学の関数では、ある変数に対応した一定の値が定まります。
プログラミングでも、これに相当するものがあります。
たとえば、一次関数で y = ( f(x) = ) 3x + 5 という式があるとして、この式の変数xのことをプログラミングでは引数(ひきすう)と呼び、変数yのことを戻り値と呼びます。

関数の大きな利点としては、再利用性というのが挙げられます。
プログラミングをしていると、同じようなことの繰り返しや、以前にやったことにある処理など、コピーペーストをするような処理がたくさんあります。
これらを、再び使いたいと思ったときに、この一連の処理を関数としてまとめてやると、楽になることが多いわけですね。

他にも、人間にとって読みやすいものになることもあります。
複雑なことをプログラムで行うと、後々コードを読み返したときに、カオスになっていることがよくありますが、そのカオスを少しでも秩序あるものにしてやるために、関数化してやることもありますね。

今回のミソ

  • 関数を使うと再利用性が増す
  • 関数を使うと可読性が増す
  • 関数には引数と戻り値がある

#03 - 関数の定義

今回は…

今回はD言語での関数の定義方法を説明します。
さて、数学的な関数の具体例として、f(x) = 3x + 5 という表現は高校生のあたりで習うはずですね。 関数の定義です。
これと同じ「関数の定義」をD言語で書くと、

real f(real x)
{
    return 3*x + 5;
}

というようになります。
いちばん最初の real というのが戻り値の型を示していて、real xという部分で引数の型と変数名を示します。
また、今までおまじないだったreturnというものが出てきますね。
returnというのは、そこに書かれたものを、戻り値として関数を呼んだところ(使ったことろ)に返しますということです。
この場合は引数は実数で、戻り値も実数ですね。

同様に、半径から円の面積を求めるための関数は、数学では
A(r) = πr2
という風に書きました。プログラミングでは、

real A(real r)
{
    return 3.141592 * r * r;
}

というように書きます。
これも、引数が実数で、戻り値も実数です。

ところで、これら関数は、 writef などと同様、プログラミングのコードの中で f(1) や A(10) などのように使いますが、
real A(real r) と書いた時の r と、 A(10) と書いた時の10では、同じ「引数」でも特別に意味を分けて使用したい場合には呼び方が若干異なります。
定義をする時の引数(変数)のことを、仮引数と呼び、使用するときに関数の中に入力する引数を実引数と呼びます。

それでは、実際に関数を定義し、使用する例をソースコードで示します。

今回のミソ

  • 戻り値の型 関数名(変数の型 変数名, 変数の型2 変数名2 ....){ /+......+/ } というように定義する
  • 定義する場所の引数は「仮引数」
  • 使用するときの引数は「実引数」

サンプルコード

// おまじない std.stdio のモジュールを読み込む
import std.stdio;

// 一つ目の関数
// f(x) = 3x + 5
// この場合引数は一つで、real型の値をとります。
// xは仮引数になる変数です。
// return というのはそこに書かれた値を戻り値にするということ。
// return で返される値の型は、 real f( ... のあたりの、最初の realの部分で決定されます。
real f(real x)
{
    // 戻り値は 3*x + 5 として計算された値
    return 3*x + 5;
}

// 二つ目の関数
// 円の面積を求めます。
// この場合も引数がreal型の値一つ、戻り値はreal型になります。
real A(real r)
{
    // 戻り値は 円の面積を計算した値
    return 3.141592*r*r;
}

// いままでおまじないとして見ていましたが、このmainも関数です。
// 基本的には、プログラムで最も最初に呼ばなくても自動的に実行される関数です。
// 引数の型は、複数の文字列で、戻り値はint型となっています。
int main(char[][] arg)
{
    
    // 円の半径は、3x+5の計算をした値とする。
    real CircleRadius = f(3);
    
    // 円の面積は円の半径から求める。
    real CircleArea = A( CircleRadius );
    
    // 面積を計算する。
    writef(CircleArea);
    
    // プログラムの戻り値。 0 で正常終了します。
    // 異常終了のときには-1や1などを返すのが一般的です。
    return 0;
}

実行結果

615.752

まとめ

というわけで、今回は関数の定義について説明しました。
次は、関数の使い方です。

#04 - 関数の使い方

今回は…

そんなわけで、今回は関数の使い方について説明します。 といっても、前回のプログラムですでに一応関数を使っているので、今回の内容としては、もうちょっと高度な、いわゆる数学でいうところの合成関数や2変数関数の定義と使い方、それから標準関数の使い方なんかについて説明…というか紹介します。

今回のミソ

  • import モジュール名; で、使いたい関数の入っているモジュールをインポートするとその関数が使えるようになる
  • 複数の引数をとる関数も定義できる。
  • 数学でいう合成関数のようなことも可能。

サンプルコード

// writefやwritefln、readln関数を使用するためにインポートするのは
// std.stdio というモジュール
import std.stdio;

// sinやcos、平方根を求めるためのsqrtなどの数学的な関数を
// 使用するためにはこのモジュールをインポートする
import std.math;

// 文字列から数値に変換する場合はこのモジュールをインポート
// たとえば、文字列から整数に変換するのはtoInt関数
// 文字列から実数に変換するのはtoReal関数
import std.conv;

// 数値から文字列に変換したり、文字列に関する操作を
// 行う場合にはこのモジュールをインポート
// たとえば 行末文字を削るchomp関数や、
// 特定の文字あるいは文字列を見つけるfind関数など
// が使えるようになります。
import std.string;

// 2変数関数の定義。
// この関数は、数学のグラフで、原点から (x, y) の点
// までの距離を求めます
real DistanceFromOrigin(real x, real y)
{
    // 三平方の定理を使います√(x^2 + y^2)
    // 平方根を求める関数は、 std.math モジュールの中の sqrt関数
    return sqrt( x*x + y*y );
}

// 4変数関数の定義
// この関数は点から点までの距離を求めます
real DistanceFromPointToPoint(real x1, real y1, real x2, real y2)
{
    // これもやっぱり三平方の定理
    return sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) );
}

// main関数
int main(char[][] arg)
{
    
    // writefln や writef は、std.stdioをインポートすることで使うことができます。
    writefln("原点と点(10,10)からの距離を求めます。");
    writef("まずはx座標を入力 : ");
    
    // 入力を求めるのに、今までに toInt( chomp( readln() ) )
    // のようなことをしていましたが、まさにこれは合成関数ですね。
    // readln() で読み込んだ文字列を、
    // chomp() で改行コードを削り取り、
    // toInt() で実数に変換するという流れを合成関数によって行っています。
    // もっとも、プログラミングでは特に合成関数と意識するようなことはありません。
    // "(" と ")" に囲まれた部分は先に評価(=実行)されるので、
    // より深い()に囲まれた部分から先に関数が処理されているだけなのです。
    // 今回は整数ではなく、実数なのでtoReal関数を使います
    real x = toReal( chomp( readln() ) );
    
    writef("つぎにy座標を入力 : ");
    real y = toReal( chomp( readln() ) );
    
    // 原点からの距離を表示する
    writefln( "原点からの距離は : %f", DistanceFromOrigin(x, y) );
    
    // 点(10, 10)からの距離を表示する
    writefln( "点(10, 10)からの距離は : %f", DistanceFromPointToPoint(10, 10, x, y) );
    
    // 正常終了
    return 0;
}

実行結果

原点と点(10,10)からの距離を求めます。
まずはx座標を入力 : 50
つぎにy座標を入力 : 10
原点からの距離は : 50.990195
点(10, 10)からの距離は : 40.000000

まとめ

というわけで、今回は関数の使い方について説明しました。
モジュールについてもちょっとだけ触れました。
今回は引数も戻り値もrealのものばかり定義しましたが、引数にchar[]などとすれば文字列なども引数にできますし、戻り値もchar[]型などにすることもできます。
また、今回紹介した標準関数以外の関数もたくさんあります。
多すぎるので紹介はできませんが、案ないならすることができます。
http://www.kmonos.net/alang/d/phobos/phobos.html
準公式のページですが、ここを見ると標準関数のほとんどが記載されています。
この中から、モジュール名から推測したりして、目的の関数を捜すわけです。

#summary - まとめ

第07章のミソ

  • 関数とは、機能を持った数
  • 関数に与えた値と返ってくる値はそれぞれ対応している
  • 数学での関数の定義は f(x) = 3x + 5 のように書く
  • sin(x)やcos(x)などの有名なものもある
  • 関数の中身はブラックボックスとして扱うことができる
  • 関数を使うと簡単に書ける場合がある。
  • 関数を使うと再利用性が増す
  • 関数を使うと可読性が増す
  • 関数には引数と戻り値がある
  • 戻り値の型 関数名(変数の型 変数名, 変数の型2 変数名2 ....){ /+......+/ } というように定義する
  • 定義する場所の引数は「仮引数」
  • 使用するときの引数は「実引数」
  • import モジュール名; で、使いたい関数の入っているモジュールをインポートするとその関数が使えるようになる
  • 複数の引数をとる関数も定義できる。
  • 数学でいう合成関数のようなことも可能。

宿題

今回は合成関数のようなものだとして扱った
toInt( chomp( readln() ) )
や、
toReal( chomp( readln() ) )
という表現。
今回のような例では割とよく使うと思いませんか?
InputInt() や InputReal() といったような関数にしてしまってもいいと思いませんか?
やってみましょう。
以下のmain関数を一切書き変えずに、その下のような出力結果を出してください
int main(char[][] args)
{
    writef("整数を入力 : ");
    int a = InputInt();
    writef("入力された整数は");
    writefln(a);
    writef("実数を入力 : ");
    real b = InputReal();
    writef("入力された実数は");
    writefln(b);
    return 0;
}

整数を入力 : 5
入力された整数は5
実数を入力 : 1.6
入力された実数は1.6

コメント

さて、今章では今までおまじないだった部分が解決されましたね。
標準関数以外にも、いろいろな人が開発した様々な関数があります。
ライブラリという形で提供されているのですが、まぁ、この話はまた別の機会にでも。

さて、次回は、配列です。
今まで文字列として扱ってきた char[] というものですが、これは文字の配列で成り立っています。
そんな話を次章ではしていきます。
そんなわけで、宿題できたら、あるいは予想ついたら次にいきましょう~

ページトップ / 目次 / 次へ
Copyright©SHOO All rights reserved. / LastModified : 2007/12/12(水)[05:57:20]