2014年08月05日
Posted by 屋台ブルー at
2014年08月05日00:00 Comment(0)
Swiftで遊ぼう! - 28 プロトコールの理解も時間がかかりそう。
ここまでプログラミングの構造理解に苦しむと思わなかった。プロトコールをみていても何気に出てくる例文で使用されているアルゴリズムもちんぷんかんぷんだ。私みたいに頭の悪い人間は、こんなものだと理解したつもりで全体像を眺めないとどうしようもないね。困ったモノだ(^_^;)
プロトコールの説明は次に乱数発生の例文を取りあげている。
protocol RandomNumberGenerator {
func random() -> Double
}
class LinearCongruentialGenerator: RandomNumberGenerator {
var lastRandom = 42.0
let m = 139968.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c) % m)
return lastRandom / m
}
}
let generator = LinearCongruentialGenerator()
println("ここにある乱数は: \(generator.random())")
println("さらにもう一つの乱数は:\(generator.random())")
しかしだよ、しかし、次のクラスを宣言しても同じなんだけどね。
class LinearCongruentialGenerator {
var lastRandom = 42.0
let m = 139968.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c) % m)
return lastRandom / m
}
}
let generator = LinearCongruentialGenerator()
println("ここにある乱数は: \(generator.random())")
println("さらにもう一つの乱数は:\(generator.random())")
プロトコールを追加していても追加していなくても同じ振る舞いをする。
結果は以下のように表示される。
ここにある乱数は: 0.37464991998171
さらにもう一つの乱数は:0.729023776863283
さて、ちょっと考えなきゃいけないのが最初のプロトコール宣言。メソッドを1つインスタンスとして作り出す汎用プロトコール。これだけでは使えないけど、クラスやStructure、enumerationに組み込んで使用することができる。
protocol RandomNumberGenerator {
func random() -> Double
}
random()という乱数発生のメソッドが定義されている。このメソッド(どういう理屈で乱数を発生させているのかさっぱり分からないが)は、呼び出す毎に0.0から1.0の間(両端を含む)の乱数を発生させている。
次のLinearCongruentialGeneratorクラスは、このプロトコールを拡張して疑似乱数を発生させるようにしている。
さて、疑似乱数が何のことかちょっと調べてみると、コンピューターで真の乱数を発生させるが難しいということが分かった。そのため計算手法で乱数を発生させる方法が色々考えられ、その1つが線形合同法を使った疑似乱数発生という説明らしい。
0よりも大きな数 a と c を適当に指定する。
a と c よりも大きな数 m を適当に決める。
さらに、m よりも小さく0以上である lastRandm を決める。
次の値 lastRandm’ を計算する
乱数の計算式)
lastRandom’=(lastRandom * a + c) % m
適当な初期値lastRandmを入れて乱数lastRandom'を出して、次はこのlastRandom'を使って新たな乱数を発生させるという手順になる。
おわかりのように初期値lastRandomが毎回同じだと同じ乱数が発生されてしまうのでX値は変わらないと意味がない。
とそういう話で、protocolはある種抽象的なメソッドのブループリントになるため必ず他のクラスで実装してインスタンス生成が必要ということでしょうね。でも上記の説明のようにクラスが1つの場合、protocolをつくる必要性がわからない(^^;)
プロトコールの説明は次に乱数発生の例文を取りあげている。
protocol RandomNumberGenerator {
func random() -> Double
}
class LinearCongruentialGenerator: RandomNumberGenerator {
var lastRandom = 42.0
let m = 139968.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c) % m)
return lastRandom / m
}
}
let generator = LinearCongruentialGenerator()
println("ここにある乱数は: \(generator.random())")
println("さらにもう一つの乱数は:\(generator.random())")
しかしだよ、しかし、次のクラスを宣言しても同じなんだけどね。
class LinearCongruentialGenerator {
var lastRandom = 42.0
let m = 139968.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c) % m)
return lastRandom / m
}
}
let generator = LinearCongruentialGenerator()
println("ここにある乱数は: \(generator.random())")
println("さらにもう一つの乱数は:\(generator.random())")
プロトコールを追加していても追加していなくても同じ振る舞いをする。
結果は以下のように表示される。
ここにある乱数は: 0.37464991998171
さらにもう一つの乱数は:0.729023776863283
さて、ちょっと考えなきゃいけないのが最初のプロトコール宣言。メソッドを1つインスタンスとして作り出す汎用プロトコール。これだけでは使えないけど、クラスやStructure、enumerationに組み込んで使用することができる。
protocol RandomNumberGenerator {
func random() -> Double
}
random()という乱数発生のメソッドが定義されている。このメソッド(どういう理屈で乱数を発生させているのかさっぱり分からないが)は、呼び出す毎に0.0から1.0の間(両端を含む)の乱数を発生させている。
次のLinearCongruentialGeneratorクラスは、このプロトコールを拡張して疑似乱数を発生させるようにしている。
さて、疑似乱数が何のことかちょっと調べてみると、コンピューターで真の乱数を発生させるが難しいということが分かった。そのため計算手法で乱数を発生させる方法が色々考えられ、その1つが線形合同法を使った疑似乱数発生という説明らしい。
0よりも大きな数 a と c を適当に指定する。
a と c よりも大きな数 m を適当に決める。
さらに、m よりも小さく0以上である lastRandm を決める。
次の値 lastRandm’ を計算する
乱数の計算式)
lastRandom’=(lastRandom * a + c) % m
適当な初期値lastRandmを入れて乱数lastRandom'を出して、次はこのlastRandom'を使って新たな乱数を発生させるという手順になる。
おわかりのように初期値lastRandomが毎回同じだと同じ乱数が発生されてしまうのでX値は変わらないと意味がない。
とそういう話で、protocolはある種抽象的なメソッドのブループリントになるため必ず他のクラスで実装してインスタンス生成が必要ということでしょうね。でも上記の説明のようにクラスが1つの場合、protocolをつくる必要性がわからない(^^;)