講義メモ

・p.185「フィボナッチ数列を求める」から

p.181 階乗を計算する(再掲載)

・階乗とは、ある正の整数において、その数から1までの全整数の積
 ※ 実質的にはその数から2までの全整数の積になる
・整数nの階乗を「n!」で表し、例えば、2!は2、3!は6、4!は24、5!は120、…
・これを逆順で展開すると
 5! = 5×4×3×2×1
 4! =    4×3×2×1
 3! =       3×2×1
・なので、5!=5×4!、4!=4×3! であることから「n! = n×(n-1)!」が導ける。
・これをメソッドFactにすると、
 int CalcFact(int n) { //nの階乗
  return n * CalcFact(n - 1); //n×(n-1)!を返す(再帰する)
 }
・これに、再帰の終了条件として「0の階乗は1」を加えると良い
 int CalcFact(int n) { //nの階乗
  return (n > 0) ? n * CalcFact(n - 1) : 1; //nが0超ならn×(n-1)!を返す(再帰する)でなければ1を返す
 }
・p.182 fact01.csは上記を展開したメソッドになっている

提出フォロー:アレンジ演習:p.182 fact01.cs

・CalcFact(int n)メソッドを上記を用いてシンプルにしよう

作成例

//アレンジ演習:p.182 fact01.cs
using System;
class Fact {
    public long CalcFact(int n) { //n!を返す
        return (n > 0) ? n * CalcFact(n - 1) : 1; //nが0超ならn×(n-1)!を返す(再帰する)でなければ1を返す
    }
}
class fact01 {
    public static void Main() {
        Fact f = new Fact();
        for (int i = 0; i <= 20; i++) {
            Console.WriteLine("{0}! = {1}", i, f.CalcFact(i));
        }
    }
}

p.185 フィボナッチ数列を求める

・フィボナッチ数列は統計やシミュレーションなどに用いる増加速度をもつ数字の並び。
・先頭2値が1で、それ以降は前2値の和になる
・実例: 1,1,2,3,5,8,13,21,34,55,…
・よって、n番目のフィボナッチ数はn-1番目とn-2番目の和として、再帰で表現できる

p.185 fibonacci.cs

//p.185 fibonacci.cs
using System;
class fibo {
    public long CalcFibo(int n) { //フィボナッチ数列のn番目を返す
        long fb;
        if (n == 1 || n == 2) { //先頭2要素は1固定(再帰の終了条件でもある)
            fb = 1;
        } else {
            fb = CalcFibo(n - 1) + CalcFibo(n - 2); //3値目以降は前2値の和
        }
        return fb;
    }
}
class fibonacci {
    public static void Main() {
        fibo f = new fibo();
        for (int i = 1; i <= 30; i++) {
            Console.WriteLine("f({0}) = {1}", i, f.CalcFibo(i));
        }
    }
}

アレンジ演習:p.185 fibonacci.cs

・条件演算子を用いて記述をシンプルにしよう

作成例

//アレンジ演習:p.185 fibonacci.cs
using System;
class fibo {
    public long CalcFibo(int n) { //フィボナッチ数列のn番目を返す
        return  (n == 1 || n == 2) ? 1 : CalcFibo(n - 1) + CalcFibo(n - 2); //3値目以降は前2値の和
    }
}
class fibonacci {
    public static void Main() {
        fibo f = new fibo();
        for (int i = 1; i <= 30; i++) {
            Console.WriteLine("f({0}) = {1}", i, f.CalcFibo(i));
        }
    }
}

p.188 refとout(値渡しと参照渡し)

・C#においてメソッドの引数は値渡しが基本であり、値のコピーが行われる
・よって、メソッド内で引数を変更しても、呼び出し側の指定した引数の値は変わらない
・p.189 swap01.csが失敗例で、Mainメソッドで定義して引数に指定しているxとyは、Swap関数の仮引数xとyとは(たとえ同名でも)無関係
・C/C++では参照型の場合に参照渡しによりこれを解決できるが、C#では参照型でも値渡しになる
・なお、配列などのようにデータ構造を渡した場合は、構造の占有位置を示す値が値渡しされるので、受け取った側で同じオブジェクトを
 用いるため、参照渡しになる

p.191 charngearray01.cs

//p.191 charngearray01.cs
using System;
class change {
    public void modify(int[] array) { //引数が配列なので実質的に参照渡し
        int n = array.Length; //要素数を得て
        for (int i = 0; i < n; i++) { //全要素について繰返す
            array[i] *= 2; //要素値を2倍にする
        }
    }
}
class changearray01 {
    public static void Main(){
        change c = new change();
        int[] myarray = new int[3]{1, 2, 3};
        Console.WriteLine("----modifyメソッド実行前----");
        int i = 0;
        foreach (int x in myarray) { //配列myarrayの全要素について繰返す
            Console.WriteLine("myarray[{0}] = {1}", i, x); //値を表示
            i++;
        }
        c.modify(myarray); //要素値を2倍にする
        Console.WriteLine("----modifyメソッド実行後----");
        i = 0;
        foreach (int x in myarray) { //配列myarrayの全要素について繰返す
            Console.WriteLine("myarray[{0}] = {1}", i, x);
            i++;
        }
    }
}

p.192 refキーワード

・値渡しとなる引数と仮引数の両方に「ref」を前置すると、参照渡しに変更される
・なお、この引数は事前に初期化が必要だが、変数名は同じである必要はない

p.193 swap03.cs

//p.193 swap03.cs
using System;
class myclass {
    private int temp;
    public void swap(ref int x, ref int y) { //仮引数xとyは参照渡しにする
        temp = x;
        x = y;    //ここでxを書き換えた結果が引数に反映する
        y = temp; //ここでyを書き換えた結果が引数に反映する
    }
}
class swap01 {
    public static void Main() {
        myclass s = new myclass();
        int x = 10, y = 20;  //引数用の変数を初期化
        s.swap(ref x, ref y); //参照渡しにより、呼び出す
        Console.WriteLine("x = {0}, y = {1}", x, y);
    }
}

p.194(outキーワード)

※ テキストではrefの代わりに無条件にoutが利用できるような説明になっているが、制限もある
・refに代わりにoutを指定すると、事前の初期化が不要になる
・ただし、out指定の仮引数は初期化されていないことから、代入の右辺には記述できない
・よって、p.193 swap03.csの「ref」を「out」にするとエラーになる
・また、古いバージョンのC#では利用できない

p.194 outkeyword01.cs

//p.194 outkeyword01.cs
using System;
class MyClass{
    public void Square(double x, double y, out double s) { //仮引数sは参照渡し
        s = x * y; //よってsをreturnする必要はない
    }
}
class outkeyword01 {
    public static void Main() {
        double a = 125.3, b = 16.25, c;
        MyClass mc = new MyClass();
        //cには値を代入していません
        mc.Square(a, b, out c); //初期化していないcを参照渡しできる
        Console.WriteLine("縦{0}m, 横{1}mの長方形の面積は{2}平方メートル", a, b, c);
    }
}

補足:p.194 outkeyword01.csについて

・Squareメソッドは1値を返すようになっているので、outは必須ではない。下記で可能。
    public double Square(double x, double y) { 
        return x * y; 
    }

アレンジ演習:p.194 outkeyword01.cs

・引数xとyの和と積を返すメソッド public void AddMul(double x, double y, out double add, out double mul) にしよう

作成例

//アレンジ演習:p.194 outkeyword01.cs
using System;
class MyClass{
    public void AddMul(double x, double y, out double add, out double mul) { //仮引数add,mulは参照渡し
        add = x + y; //よってreturnする必要はない
        mul = x * y; //よってreturnする必要はない
    }
}
class outkeyword01 {
    public static void Main() {
        double a = 125.3, b = 16.25, c, d;
        MyClass mc = new MyClass();
        mc.AddMul(a, b, out c, out d); //初期化していないc、dを参照渡しできる
        Console.WriteLine("和は{0}, 積は{1}", c, d);
    }
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です