Upload
owen-brewer
View
32
Download
4
Embed Size (px)
DESCRIPTION
計算機プログラミング I 第 8 回. 素数を見つけるアルゴリズム 継承とインスタンスメソッド オブジェクトに機能を加える オブジェクトの機能を変更 クラスの設計. 単純な方法 : i が素数かどうか 2 ~ (n-1) で割ってみる→約 i 回の計算 i が 2 から n まで調べる→ 2+3+…+n= 約 n 2 回の計算 エラトステネスのふるい i 番目が素数→ n/i 回の計算 i=2 から n-1 まで全て素数だったとして n/2 + n/3+…+n/(n-1) < an log(n) 回の計算 ( 素数の存在確率を無視 ) - PowerPoint PPT Presentation
Citation preview
計算機プログラミングI (増原) 2003年度
1
計算機プログラミング I第 8 回
•素数を見つけるアルゴリズム•継承とインスタンスメソッド
–オブジェクトに機能を加える–オブジェクトの機能を変更
•クラスの設計
計算機プログラミングI (増原) 2003年度
2
2 から n が素数かどうかを判定するのに必要な計算回数
• 単純な方法 : –i が素数かどうか 2 ~ (n-1)
で割ってみる→約 i 回の計算–i が 2 から n まで調べる→ 2
+3+…+n= 約 n2 回の計算• エラトステネスのふるい
–i 番目が素数→ n/i 回の計算–i=2 から n-1 まで全て素数
だったとして n/2 + n/3+…+n/(n-1) < an log(n) 回の計算
( 素数の存在確率を無視 )–ただし大きさ n の配列が必
要
• フェルマーのテスト ( 単純 )– 1 回のテストは ai の計算→ i 回
の掛け算– i が 2 から n まで各 b 回テスト→
約 bn2 回の計算• フェルマーのテスト ( 工夫 )
– ai の計算=ai/2 の計算 +1 回=(ai/4 の計算 +1 回 )+1 回 =…=a0 の計算 +1 回 + ・・・ +1 回= 約 log(i) 回
– i が 2 から n まで各 b 回テスト合計 bn log(n) 回以下の計算
– 確率的
計算機プログラミングI (増原) 2003年度
3
計算量2 から n が素数かどうか• 単純な方法 : 約 n2 回• エラトステネスのふるい
–約 n log(n) 回–大きさ n の配列が必要
• フェルマーのテスト ( 単純 ):約 bn2 回
• フェルマーのテスト ( 工夫 ):約 bn log(n) 回
• 定数を無視して考えたものを「計算量」という– O(n2), O(n log(n)) のよ
うに書く– おおまかな計算時間
( とメモリの量 ) を比べるため
– 例 : 非常に大きな素数を見つけたい場合
計算機プログラミングI (増原) 2003年度
4
n2 回と n log(n) 回の違い
01E+152E+153E+154E+155E+156E+157E+158E+159E+15
0 2E+07 4E+07 6E+07 8E+07 1E+08
n*nn log(n)
計算機プログラミングI (増原) 2003年度
5
最大のメルセンヌ素数分散コンピューティングで栄誉
ある大発見を (ZDNN 2001/12/17)…… コンピュータを使って,こ
れまでに発見された中で世界最大の素数を発見した。……メルセンヌ素数と呼ばれる特殊なタイプの素数を発見するプロジェクトに参加……発見した素数は, 2 の 1346万 6917 乗マイナス 1 ,桁数は 405万 3946 桁にもなる。
メルセンヌ素数は,「 2 の p 乗マイナス 1 ( p は普通の素数)」という特殊なタイプの素数を研究していたフランスの修道士, Marin Mersenne ( 1588 ~ 1648 )にちなんで名付けられた。
メルセンヌ素数は普通の素数よりもはるかに珍しい。これまでのところ, 39 のメルセンヌ素数が発見されている……発見した数値がメルセンヌ素数であることを確認するのに 42 日間かかった。その後研究者がワークステーション 1 台を使って, 3 週間かけて確認作業を行った。http://www.zdnet.co.jp/news/0112/17/e_distributed.html
40 番目のメルセンヌ素数の発見 ! (2003/12/3)
値は 220,996,011-1
桁数は 6,320,430 桁http://www.mersenne.org/
計算機プログラミングI (増原) 2003年度
6
継承とインスタンスメソッド• オブジェクトに機能を加えたい !
だけど、いままでのプログラムは変えたくない !だからといってプログラムのコピーもしたくない !
継承を使って新しいクラスを作る新しいインスタンス変数を追加する新しいインスタンスメソッドを追加する
• オブジェクトの機能を変更したい ! だけど ( 以下略 ) 継承を使って新しいクラスを作る
すでにあるインスタンスメソッドを再定義する
計算機プログラミングI (増原) 2003年度
7
例題 : タートルで n 角形を描く• いままでの Turtle オブジェクトができること
–前進 (fd) ・回転 (lt) 等の指示を受ける• Turtle オブジェクトに「長さ l の n 角形を描け」という指示が出せたなら・・・
Turtle m = new Turtle();m.polygon(100,5); // 1 辺 100 の 5 角形
• でも…–Turtle クラスは変更したくない–Turtle.java のコピーを作るのは面倒
計算機プログラミングI (増原) 2003年度
8
例題 : タートルで n 角形を描く• Turtle クラスを拡張して、 House クラスを定義する• House クラスにインスタンスメソッドを追加する
–「 n 角形を描く」 polygon
–「家の形を描く」 house
House オブジェクトに対しては、 fd, lt 等の他に追加された polygon, house メソッドも呼び出せる
※ House オブジェクトを使っていないプログラムには影響がない !
計算機プログラミングI (増原) 2003年度
9
n 角形の描き方を知っているタートルがいたら・・・
House ・・・Turtle のかわりのク
ラス名
House ・・・Turtle のかわりのク
ラス名
Turtle オブジェクトと
同じように使える
Turtle オブジェクトと
同じように使える
Turtle にはないメソッドもあるTurtle にはないメソッドもある
public class T61 { public static void main(String[] args){ TurtleFrame f = new TurtleFrame( ); House m = new House( ); int s = 50; f.add(m); m.house(s); m.up( ); m.fd(s * 2); m.down( ); m.polygon(3, s / 2); m.up( ); m.fd(s); m.down( ); m.polygon(10, s / 5); }}
計算機プログラミングI (増原) 2003年度
10
n 角形の描き方を知っているタートルの定義
Turtle に機能を追加したクラスを作ると宣言Turtle に機能を追加したクラスを作ると宣言
追加される機能( メソッド )
追加される機能( メソッド )
自分自身を使ってn 角形を描く
自分自身を使ってn 角形を描く
自分自身を使って家の形を描く
自分自身を使って家の形を描く
public class House extends Turtle { public void polygon(int n, int s){ int a = 360/n; for(int j = 0; j < n; j++){ fd(s); rt(a); } } public void house(int s){ polygon(4,s); fd(s); rt(30); polygon(3,s); lt(30); bk(s); }}
計算機プログラミングI (増原) 2003年度
11
n 角形の描き方を知っているタートルの定義
自分自身 (=m) に対するメソッドの実行→m.fd(s) と同じ
→ m が前進
自分自身 (=m) に対するメソッドの実行→m.fd(s) と同じ
→ m が前進
例 :m.polygon(50,3) を実行
→m に対して「多角形を描け」
→ このメソッドが実行
例 :m.polygon(50,3) を実行
→m に対して「多角形を描け」
→ このメソッドが実行
自分自身 (=m) に対するメソッドの実行
追加したメソッドも実行可
自分自身 (=m) に対するメソッドの実行
追加したメソッドも実行可
public class House extends Turtle { public void polygon(int n, int s){ int a = 360/n; for(int j = 0; j < n; j++){ fd(s); rt(a); } } public void house(int s){ polygon(4,s); fd(s); rt(30); polygon(3,s); lt(30); bk(s); }}
文法 : “static” が無い以外はクラスメソッドと
同じ
文法 : “static” が無い以外はクラスメソッドと
同じ
計算機プログラミングI (増原) 2003年度
12
例題 2: n 角形を分割して描く亀• 「長さ l の n 角形を分割して描く」 Turtle
–「 1 ステップ進め」と言われると、 n 角形の 1 辺だけを描く
–「 1 ステップ進め」というときに、いちいち 1 辺の長さや何角形であるかを指示したくない 次に「進め」と言われたら
• まだ進むべきか ?• 何度曲がるか ?• 何歩進むか ?
次に「進め」と言われたら• まだ進むべきか ?• 何度曲がるか ?• 何歩進むか ?
Stepper m = 長さ 50 の 5 角形を描く亀 ;Stepper m1 = 長さ 30 の 8角形を描く亀 ;m.step(); //5 角形の 1 辺を描くm1.step(); //8角形の 1 辺を描く・・・
計算機プログラミングI (増原) 2003年度
13
例題 2: n 角形を分割して描く亀• 各 Turtle が「 1 辺の長さがいくつの」「何角形」を
「何番目の辺」まで描いたかを覚える必要がある → インスタンス変数
• Turtle を拡張して Stepper クラスを作る– インスタンス変数を定義する
• 1 辺の長さ• 何角形か• 何番目の辺まで描いたか
– 「 1 ステップ進め」インスタンスメソッドを定義• 全ての辺を描き終えたか ? まだだったら• 前進・回転して• 「何番目の辺まで描いたか」を 1 増やす
オブジェクトに状態を持たせる
計算機プログラミングI (増原) 2003年度
14
6.4 インスタンス変数自分がいま• 何角形を描いているのか • 1辺の長さ• 何番目の辺を描いているのかを覚える
• ローカル変数と同様に• 値をとり出す• 値をしまう
ことができる
• オブジェクトごとに用意される→ 前回のメソッド実行時に
しまわれた値がそのまま残っている
j=j+1;if(j==n) ...と同じ
インスタンス変数の宣言
インスタンス変数の宣言public class Stepper extends Turtle{
public int n; public int size; private int j = 0; public static final int ALREADY_FIN = 0; public static final int JUST_FIN = 1; public static final int NOT_FIN = 2; public int step() { if(j >= n) return ALREADY_FIN; fd(size); rt(360/n); if(++j == n) return JUST_FIN; return NOT_FIN; } public void reset() { j = 0; }}
計算機プログラミングI (増原) 2003年度
15
6.4 インスタンス変数自分がいま• 何角形を描いているのか • 1辺の長さ• 何番目の辺を描いているのかを覚える
• ローカル変数と同様に• 値をとり出す• 値をしまう
ことができる
• オブジェクトごとに用意される→ 前回のメソッド実行時に
しまわれた値がそのまま残っている
j=j+1;if(j==n) ...と同じ
public class Stepper extends Turtle{ public int n; public int size; private int j = 0; public static final int ALREADY_FIN = 0; public static final int JUST_FIN = 1; public static final int NOT_FIN = 2; public int step() { if(j >= n) return ALREADY_FIN; fd(size); rt(360/n); if(++j == n) return JUST_FIN; return NOT_FIN; } public void reset() { j = 0; }}
public class T62{ public static void main(String[] args){ TurtleFrame f = new TurtleFrame(); Stepper m1 = new Stepper(); f.add(m1); Stepper m2 = new Stepper(); f.add(m2); m1.n = 4; m1.size = 100; m2.n = 3; m2.size = 100; ...
public class T62{ public static void main(String[] args){ TurtleFrame f = new TurtleFrame(); Stepper m1 = new Stepper(); f.add(m1); Stepper m2 = new Stepper(); f.add(m2); m1.n = 4; m1.size = 100; m2.n = 3; m2.size = 100; ...
j=j+1;(++j == n)
計算機プログラミングI (増原) 2003年度
16
6.5 コンストラクタ• インスタンス変数 = オブジェクトごとにある状態• オブジェクトを作る (new) と、初期化をする ( 例 : インスタンス変数に適当な値をしまう ) これを一体化したい ! コンストラクタ
• オブジェクトが作られたときに実行されるメソッド• 文法 : クラス名 (引数の型 引数の名前 , ...) { 文 ; ... }
( メソッド定義に似ている。違うのは返り値の型が無い点と名前 )
• 継承とコンストラクタ–子クラスのコンストラクタから親クラスのコンストラクタを呼び出す
super(引数 , 引数 , ...);–子クラスのコンストラクタは、一番初めにこれをしなければいけない–省略すると「引数の無いコンストラクタ」が自動的に呼び出される– しかし親クラスが「引数の無いコンストラクタ」を定義していないとエラー
計算機プログラミングI (増原) 2003年度
17
public class Stepper extends Turtle{ public int n; public int size; private int j = 0;
Stepper(int x, int y, int angle, int n, int size) { super(x, y, angle); this.n = n; this.size = size; }... public int step() { if(j >= n) return ALREADY_FIN; ...
Stepper(int x, int y, int angle, int n, int size) { super(x, y, angle); this.n = n; this.size = size; }
コンストラクタの定義
コンストラクタの定義
super(x, y, angle);親クラスの
コンストラクタを実行... new Turtle(x,y,angle)
のときと同様
親クラスのコンストラクタを実行
... new Turtle(x,y,angle)のときと同様
Stepper
Stepper
コンストラクタの実例
Stepper[] hm = new Stepper[10]; for(int i = 0 ; i < 10; i++){
hm[i] = new Stepper(i * 50 + 25,150,0, n[i], size[i]); hm[i].setColor(c[i % c.length]); f.add(hm[i]); }
new Stepper(i * 50 + 25,150,0, n[i], size[i]);
1. Stepper オブジェクトが作られる2. コンストラクタが実行される1. Stepper オブジェクトが作られる2. コンストラクタが実行される
計算機プログラミングI (増原) 2003年度
18
例題 3: 点線を描く亀
• Turtle オブジェクトが fd したときに点線を描かせたい ! でも Turtle クラスは変更したくない !
継承とインスタンスメソッドの再定義• 例 :
Tensen House
polygon(5,50) polygon(5,50)
違い : fd メソッドを点線を描きながら進むように
再定義している
計算機プログラミングI (増原) 2003年度
19
例題 3: 点線を描く亀
点線を描く亀を作るには• House クラスの子クラス Tensen クラスを定義する• Tensen クラスに fd メソッドを定義する―― 再定義
という• そのメソッド中でペンを上げ下げしながら n 進む
Tensen House
polygon(5,50) polygon(5,50)
計算機プログラミングI (増原) 2003年度
20
点線で多角形を描くpublic class Tensen extends House{ int psize = 4; (略 : コンストラクタ ) public void fd(int s){ 長さ s の点線を描く }
public static void main(String[] args){ (略 : TurtleFrame の生成 ) Tensen m = new Tensen(); (略 ) m.polygon(5, 50); }}
1. main から実行が始まる2. Tensen オブジェクトが
作られる
3. Tensen オブジェクトの ploygon メソッドを呼び出す
4. ploygon メソッドはn 角形を描く。その際、 Tensen オブジェクトのfd は点線を描くように再定義されているので、n 角形は点線で描かれる。
計算機プログラミングI (増原) 2003年度
21
点線で多角形を描くpublic class Tensen extends House{ int psize = 4; (略 : コンストラクタ ) public void fd(int s){ 長さ s の点線を描く }
public static void main(…){ (略 : TurtleFrame の生成 ) Tensen m = new Tensen(); (略 ) m.polygon(5, 50); }}
public class House extends Turtle { public void polygon(int n, int s){ int a = 360/n; for(int j = 0; j < n; j++){ fd(s); rt(a); } }}
ここからスタート
オブジェクトを作る
メソッド呼び出し
polygon
親クラスから継承した polygon を
実行
自身の fd を呼び出し
fd
再定義されたfd が実行
Tensen
計算機プログラミングI (増原) 2003年度
22
点線で多角形を描くpublic class Tensen extends House{ int psize = 4; (略 : コンストラクタ ) public void fd(int s){ 長さ s の点線を描く }
public static void main(…){ (略 : TurtleFrame の生成 ) Tensen m = new Tensen(); (略 ) m.polygon(5, 50); }}
public class House extends Turtle { public void polygon(int n, int s){ int a = 360/n; for(int j = 0; j < n; j++){ fd(s); rt(a); } }}
再定義されたfd が実行
結果 : 点線で 5 角形が描かれる
Tensen
計算機プログラミングI (増原) 2003年度
23
extends
点線で多角形を描くしくみ
Tensen
extends
Turtle クラスfd(s):実線を描きながら前進
rt(a):右回転
…
House クラスfd(s):継承(実線を描きながら前進 )
polygon(n,s):fd を使って多角形を描く
Tensen クラスfd(s):点線を描きながら前進
polygon(n,s):継承(fd を使って多角形を描く )
…
所属
• Tensen オブジェクトへの polygon メソッドの呼び出しは、親クラスの継承された定義の実行になる
• polygon メソッド中での fd メソッドの呼び出しは、 Tensenオブジェクトへのメソッド呼び出しなので、再定義された fd が実行される
計算機プログラミングI (増原) 2003年度
24
親クラスのメソッドを使う方法• メソッドを再定義すると、
親クラスのメソッド定義が使えなくなる例 : Tensen オブジェクトの fd メソッド
• メソッド中でsuper . メソッド名 (引数 , ...)
のようにメソッドを呼び出すと、親クラスのメソッドを実行できる
例 : Tensen オブジェクトの fd メソッド中でsuper.fd(psize)
とすると、 Turtle クラスに定義された本来の fd メソッドが実行される
計算機プログラミングI (増原) 2003年度
25
点線を描くしくみpublic class Tensen extends House{ int psize = 4; (略 : コンストラクタ ) public void fd(int s){ 長さ s の点線を描く }
public static void main(…){ (略 : TurtleFrame の生成 ) Tensen m = new Tensen(); (略 ) m.polygon(5, 50); }}
public class House extends Turtle { public void polygon(int n, int s){ int a = 360/n; for(int j = 0; j < n; j++){ fd(s); rt(a); } }}
?
計算機プログラミングI (増原) 2003年度
26
点線を描くしくみpublic class Tensen extends House{ int psize = 4; (略 : コンストラクタ ) public void fd(int s){ 長さ s の点線を描く }
public static void main(…){ (略 : TurtleFrame の生成 ) Tensen m = new Tensen(); (略 ) m.polygon(5, 50); }}
public class House extends Turtle { public void polygon(int n, int s){ int a = 360/n; for(int j = 0; j < n; j++){ fd(s); rt(a); } }}
public void fd(int s){ int k, len; for(k = 0, len = 0 ; len + psize <= s; k++, len+= psize){ if(k % 2 == 0) down(); else up(); super.fd(psize); } down(); super.fd(s - len); }
public void fd(int s){ int k, len; for(k = 0, len = 0 ; len + psize <= s; k++, len+= psize){ if(k % 2 == 0) down(); else up(); super.fd(psize); } down(); super.fd(s - len); }
ペンを交互に上げ下ろししながら、psizeづつ前進する
super . メソッド名 ( 引数式 , …) 親クラスのメソッドを呼び出す
計算機プログラミングI (増原) 2003年度
27
extends
点線を描くしくみ
Tensen
extends
Turtle クラスfd(s):実線を描きながら前進
rt(a):右回転
…
House クラスfd(s):継承(実線を描きながら前進 )
polygon(n,s):fd を使って多角形を描く
Tensen クラスfd(s):ペンを上下させながらsuper.fd(psize) を呼び出し
polygon(n,s):継承(fd を使って多角形を描く )
…
所属
• Tensen オブジェクトの fd メソッドを呼び出すと、再定義されたメソッドが実行される
•再定義されたメソッド中の super.fd(psize) は親クラスの fd メソッドを実行する。結果、 Turtle クラスの fd メソッドが実行され、実線が描かれる
計算機プログラミングI (増原) 2003年度
28
extends
まとめると・・・
Tensen
extends
Turtle クラスfd(s):実線を描きながら前進
rt(a):右回転
…
House クラスfd(s):継承(実線を描きながら前進 )
polygon(n,s):fd を使って多角形を描く
Tensen クラスfd(s):ペンを上下させながらsuper.fd(psize) を呼び出し
polygon(n,s):継承(fd を使って多角形を描く )
…
所属
polygon
fd
計算機プログラミングI (増原) 2003年度
29
クラスの拡張class House extends Turtle { … } のようなとき• House は 子クラス または サブクラス• Turtle は 親クラス または スーパークラス• House オブジェクトは、 Turtle オブジェクトが持って
いる全てのメソッドを持つ ( 例 : fd)• House オブジェクトは、 Turtle オブジェクトのかわり
に使える ( 例 : TurtleFrame オブジェクトに add できる )Turtle m = new House(); ということが可能 !
• House オブジェクトは Turtle オブジェクトと違った動きをするかも知れない ( 例 : fd の再定義 )
計算機プログラミングI (増原) 2003年度
30
クラスの設計―― Turtle クラスの解剖
public class Turtle{ public Color kameColor = Color.green; TurtlePanel f; // 表示面画 double angle; // 角度 double x, y; // 位置 double dx, dy; // sin(a),-cos(a) boolean penDown; // ペン状態 Color c = Color.black; // ペンの色
// コンストラクタ public Turtle(int x,int y, int ia) { this.x = ((double)x + 0.5); this.y = ((double)y + 0.5); setangle((double)ia *Math.PI/180.0); penDown = true; }
// インスタンスメソッド public void fd(int n) {
double xx = x; double yy = y; x = xx + dx * n; y = xx + dy * n; if (penDown) { f.addLineElement((int)xx, (int)yy,
(int)x, (int)y, c); } kameShow(moveWait); } …}