Page Top

数学の関数について anchor.png

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

――さて、関数は、数学などでおなじみの、機能を持った数のことです。
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個あります。穴の開いていない赤い部分の面積は何平方メートルでしょうか。

function_circlehole.png

この例題の赤い部分の面積は、先のA(r)の関数を使って、このように表すことができます。

A(10) - 4×A(1)

半径10の円の面積から、半径1の円の面積×4つ分を引くわけですね。

数学で関数と言って、特に有名なものは、たとえば三角関数がありますね。

  • sin(x) = x -(x3/3!) +(x5/5!) -(x7/7!) ....... *1
  • cos(x) = 1 -(x2/2!) +(x4/4!) -(x6/6!) ....... *1
  • tan(x) = sin(x) / cos(x)

先ほどのA(r)などのように、自分で定義したような関数もあれば、正弦関数や余弦関数などのように、有名な人が定義してそのまま常識になってしまったような関数もあります。 関数の利点としては、正弦関数のような、中身が非常に複雑なものでも、内容はブラックボックスとして、適当な入力を与えるとそれに対応した値が返ってくるという事実だけを見て、利用することができるという点が挙げられます。
また、先ほどの三角関数のように、複雑なものを一つにまとめることで記述を簡略化することもできたりもします。

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

Page Top

今回のミソ anchor.png

  • 関数とは、機能を持った数
  • 関数に与えた値と返ってくる値はそれぞれ対応している
  • 数学での関数の定義は

    f(x) = 3x + 5

    のように書く
  • sin(x)やcos(x)などの有名なものもある
  • 関数の中身はブラックボックスとして扱うことができる
  • 関数を使うと簡単に書ける場合がある。
Page Top

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

Page Top

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

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

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

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

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

ところで、数学の関数では、ある変数に対応した一定のが定まります。
プログラミングでも、これに相当するものがあります。
たとえば、一次関数で

y = ( f(x) = ) 3x + 5

という式があるとして、この式の変数xのことをプログラミングでは引数(ひきすう)と呼び、変数yのことを戻り値と呼びます。

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

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

Page Top

今回のミソ anchor.png

  • 関数を使うと一連の処理をまとめることができる
  • 関数を使うと処理の内容をブラックボックス化できる
  • 関数を使うと再利用性が増す
  • 関数を使うと可読性が増す
  • 関数には引数と戻り値がある
Page Top

#03 - 関数の定義 anchor.png

Page Top

今回は… anchor.png

今回は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では、同じ「引数」でも特別に意味を分けて使用したい場合には呼び方が若干異なります。 定義をする時の引数(変数)のことを、仮引数と呼び、使用するときに関数の中に入力する引数を実引数と呼びます。

f(x) = 3x + 5

では、xが仮引数で、 f(10)等とした際の10が実引数ということになります。

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

Page Top

今回のミソ anchor.png

  • 関数は次のように定義します。
    戻り値の型 関数名(変数の型 変数名, 変数の型2 変数名2 ....)
    {
        /+... 処理内容 ...+/
    }
  • 定義する場所の引数は「仮引数」と呼びます
  • 使用するときの引数は「実引数」と呼びます
Page Top

サンプルコード anchor.png

filesample0703p.d
Everything is expanded.Everything is shortened.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 
 
 
-
|
|
|
|
|
!
-
-
!
!
 
-
|
|
!
-
-
!
!
 
-
|
|
!
-
|
-
!
|
-
!
|
-
!
|
-
|
!
!
// おまじない 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 );
    
    // 面積を計算する。
    writeln(CircleArea);
    
    // プログラムの戻り値。 0 で正常終了します。
    // 異常終了のときには-1や1などを返すのが一般的です。
    return 0;
}
+  Tango用はこちら
filesample0703t.d
Everything is expanded.Everything is shortened.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 
 
 
-
|
|
|
|
|
!
-
-
!
!
 
-
|
|
!
-
-
!
!
 
-
|
|
!
-
|
-
!
|
-
!
|
-
!
|
-
|
!
!
// tango.io.Stdout のモジュールを読み込む
import tango.io.Stdout;
 
// 一つ目の関数
// 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 );
    
    // 面積を計算する。
    Stdout(CircleArea).newline;
    
    // プログラムの戻り値。 0 で正常終了します。
    // 異常終了のときには-1や1などを返すのが一般的です。
    return 0;
}
Page Top

実行結果 anchor.png

1
2
$ dmd -run sample0703p.d
615.752
Page Top

まとめ anchor.png

というわけで、今回は関数の定義について説明しました。
勘の良い方は気づかれるかと思いますが、今まで取り扱った writefln や readln, chomp といったものも、関数となっています。これらは標準[[ライブラリ>Wikipedia:ライブラリ]]であらかじめ定義されているもので、それらを使うよと宣言することで使用することができるようになります。

// writefln, readln等を使うための宣言
import std.stdio;
// chomp等を使うための宣言
import std.string;
// toInt等を使うための宣言
import std.conv;

いままでおまじないとして使ってきたこれらは、関数を使えるようにする作業だったのです。
次は、関数の使い方です。

Page Top

#04 - 関数の使い方 anchor.png

Page Top

今回は… anchor.png

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

Page Top

今回のミソ anchor.png

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

サンプルコード anchor.png

filesample0704p.d
Everything is expanded.Everything is shortened.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
 
-
!
 
-
|
!
 
-
|
|
!
 
-
|
|
|
|
!
 
-
|
|
!
-
-
|
!
!
 
-
|
|
|
|
|
|
!
-
-
!
!
 
-
!
-
|
-
!
|
|
-
|
|
|
|
|
|
|
|
!
|
|
|
|
-
!
|
-
|
!
|
|
|
-
!
!
// 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変数関数の定義
// この関数は点から点までの距離を求めます
// x1 には1つ目の点のx座標
// y1 には1つ目の点のy座標
// x2 には2つ目の点のx座標
// y2 には2つ目の点のy座標
// をそれぞれ入力します。
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をインポートすることで使うことができます。
    writeln("原点と点(10,10)からの距離をそれぞれ求めます。");
    write("まずはx座標を入力 : ");
    
    // 入力を求めるのに、今までに toInt( chomp( readln() ) )
    // のようなことをしていましたが、まさにこれは合成関数ですね。
    // readln() で読み込んだ文字列を、
    // chomp() で改行コードを削り取り、
    // toInt() で実数に変換するという流れを合成関数によって行っています。
    // もっとも、プログラミングでは特に合成関数と意識するようなことはありません。
    // "(" と ")" に囲まれた部分は先に評価(=実行)されるので、
    // より深い()に囲まれた部分から先に関数が処理されているだけなのです。
    // 今回は整数ではなく、実数なのでtoReal関数を使います
    real x = to!(real)( chomp( readln() ) );
    
    write("つぎにy座標を入力 : ");
    real y = to!(real)( chomp( readln() ) );
    
    // 原点からの距離を表示する
    writefln( "原点からの距離は : %f", DistanceFromOrigin(x, y) );
    
    // 点(10, 10)からの距離を表示する
    // 長くなってしまうときは,(カンマ)などの切りの良いところで分割するとよい
    writefln(
        "点(10, 10)からの距離は : %f",
        DistanceFromPointToPoint(10, 10, x, y) );
    
    // 正常終了
    return 0;
}
+  Tango用はこちら
filesample0704t.d
Everything is expanded.Everything is shortened.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
 
-
!
 
-
!
 
-
|
!
 
-
|
|
|
!
 
-
|
|
|
!
 
-
|
|
|
!
 
 
-
|
|
!
-
-
|
!
!
 
-
|
|
|
|
|
|
!
-
-
!
!
 
-
!
-
|
-
|
|
|
!
|
|
-
|
|
|
|
|
|
|
!
|
|
|
|
-
!
|
-
|
!
|
|
|
-
!
!
// Stdout などのインスタンスオブジェクトを使うための import です。
// インスタンスオブジェクトに関しては第14章 - オブジェクト指向で取り扱います。
import tango.io.Stdout;
 
// Cin などのインスタンスオブジェクトを使うためのimportです。
import tango.io.Console;
 
// sinやcos、平方根を求めるためのsqrtなどの数学的な関数を
// 使用するためにはこのモジュールをインポートする
import tango.math.Math;
 
// 文字列から整数に変換する場合はこのモジュールをインポート
// 文字列から整数に変換するのはtoInt関数が使える
// 他にも整数から文字列に変換するためのtoString関数もある
// (ただしここでは取り扱わない)
import tango.text.convert.Integer;
 
// 文字列から実数に変換する場合はこのモジュールをインポート
// 文字列から実数に変換するのはtoFloat関数が使える
// 他にも実数から文字列に変換するためのtoString関数もある
// (ただしここでは取り扱わない)
import tango.text.convert.Float;
 
// 数値から文字列に変換したり、文字列に関する操作を
// 行う場合にはこのモジュールをインポート
// たとえば文字列の前後の半角スペースを消し去るtrim関数など
// 文字列に関するユーティリティ関数が使えるようになります。
import tango.text.Util;
 
 
// 2変数関数の定義。
// この関数は、数学のグラフで、原点から (x, y) の点
// までの距離を求めます
real DistanceFromOrigin(real x, real y)
{
    // 三平方の定理を使います√(x^2 + y^2)
    // 平方根を求める関数は、 std.math モジュールの中の sqrt関数
    return sqrt( x*x + y*y );
}
 
// 4変数関数の定義
// この関数は点から点までの距離を求めます
// x1 には1つ目の点のx座標
// y1 には1つ目の点のy座標
// x2 には2つ目の点のx座標
// y2 には2つ目の点のy座標
// をそれぞれ入力します。
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)
{
    
    // Stdoutはtango.io.Stdoutをインポートすることで使うことができます。
    // Stdout自体は関数ではなく、オブジェクトとなっていて、関数よりも
    // より複雑な処理を行うことになります。
    // 現時点では知る必要のないことです。
    Stdout("原点と点(10,10)からの距離をそれぞれ求めます。").newline;
    Stdout("まずはx座標を入力 : ").flush;
    
    // 入力を求めるのに、今までに toInt( Cin.copyln() )
    // のようなことをしていましたが、まさにこれは合成関数ですね。
    // Cin.copyln() で読み込んだ文字列を、
    // toInt() で実数に変換するという流れを合成関数によって行っています。
    // もっとも、プログラミングでは特に合成関数と意識するようなことはありません。
    // "(" と ")" に囲まれた部分は先に評価(=実行)されるので、
    // より深い()に囲まれた部分から先に関数が処理されているだけなのです。
    // 今回は整数ではなく、実数なのでtoFloat関数を使います
    real x = toFloat( Cin.copyln() );
    
    Stdout("つぎにy座標を入力 : ").flush;
    real y = toFloat( Cin.copyln() );
    
    // 原点からの距離を表示する
    Stdout.formatln( "原点からの距離は : {}", DistanceFromOrigin(x, y) );
    
    // 点(10, 10)からの距離を表示する
    // 長くなってしまうときは,(カンマ)などの切りの良いところで分割するとよい
    Stdout.formatln(
        "点(10, 10)からの距離は : {}",
        DistanceFromPointToPoint(10, 10, x, y) );
    
    // 正常終了
    return 0;
}
Page Top

実行結果 anchor.png

1
2
3
4
5
6
$ dmd -run sample0704p.d
原点と点(10,10)からの距離をそれぞれ求めます。
まずはx座標を入力 : 15
つぎにy座標を入力 : 8
原点からの距離は : 17.000000
点(10, 10)からの距離は : 5.385165
Page Top

まとめ anchor.png

というわけで、今回は関数の使い方について説明しました。
モジュールについてもちょっとだけ触れました。
今回は引数も戻り値もrealのものばかり定義しましたが、引数にchar[]などとすれば文字列なども引数にできますし、戻り値もchar[]型などにすることもできます。
また、今回紹介した標準関数以外の関数もたくさんあります。
多すぎるので紹介はできませんが、案ないならすることができます。

http://www.kmonos.net/alang/d/phobos/phobos.html

準公式のページですが、ここを見ると標準関数のほとんどが記載されています。
この中から、モジュール名から推測したりして、目的の関数を捜すわけです。

Page Top

#summary - まとめ anchor.png

Page Top

第07章のミソ anchor.png

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

宿題 anchor.png

今回は合成関数のようなものだとして扱った
to!(int)( chomp( readln() ) )
や、
to!(real)( chomp( readln() ) )
という表現。
今回のような例では割とよく使うと思いませんか?
InputInt() や InputReal() といったような関数にしてしまってもいいと思いませんか?
やってみましょう。
以下のmain関数を一切書き変えずに、その下のような出力結果を出してください

Everything is expanded.Everything is shortened.
 
-
|
|
|
|
|
|
|
|
|
!
int main(char[][] args)
{
    write("整数を入力 : ");
    int a = InputInt();
    write("入力された整数は");
    writeln(a);
    write("実数を入力 : ");
    real b = InputReal();
    write("入力された実数は");
    writeln(b);
    return 0;
}
1
2
3
4
整数を入力 : 5
入力された整数は5
実数を入力 : 1.6
入力された実数は1.6
Page Top

コメント anchor.png

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

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


Page Top

投票とコメント anchor.png

Choices Vote
大変参考になった3  
参考になった0  
あまり参考にならなかった0  
まったく参考にならなかった0  

No comment. コメント​/Articles​/D言語入門講座​/第07章 - 関数1Edit

Name:

*1 右辺はテイラー展開されたもの

Front page   Freeze Diff Backup Copy Rename ReloadPrint View   New Page Page list Search Recent changes   Help   RSS of recent changes (RSS 1.0) RSS of recent changes (RSS 2.0) RSS of recent changes (RSS Atom) Powered by xpWiki
Counter: 1843, today: 1, yesterday: 0
Princeps date: 2009-04-20 (Mon) 22:47:44
Last-modified: 2009-04-20 (Mon) 22:47:44 (JST) (4247d) by SHOO
メインメニュー

ログイン

ユーザー名:


パスワード:





パスワード紛失  |新規登録

Menu