これはObjective-Cを学習するためにProjectEulerの問題を解いていこうという思いつきだけで始まったいつまで続くかわからない企画である。
Problem 2
フィボナッチ数列の項は前の2つの項の和である. 最初の2項を 1, 2 とすれば, 最初の10項は以下の通りである.
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
数列の項の値が400万を超えない範囲で, 偶数値の項の総和を求めよ.
回答
int fibo = 0;
int sum = 2;
int num1 = 1;
int num2 = 2;
while (fibo < 4000000) {
fibo = num1 + num2;
if (fibo%2 == 0) {
sum = sum + fibo;
}
num1 = num2;
num2 = fibo;
}
NSLog(@"answer : %d",sum);
//2013-04-29 11:11:11.525 Euler[30400:303] answer : 4613732
単純に回答を求めれば上記のようになる。しかしいくつか納得の行かないことがある。
whileの中で変数sumに偶数値を加算していくが、初期値の1,2を足した3からwhileが始まる。つまり正答するために変数sumの初期値を2にしている。これは美しくない。
「Objective-Cを学習するため」という目的があるんだからもっとObjective-Cの機能を活用したい。
そんなわけで、フィボナッチ数を返すジェネレータ的なクラスを作ってみようと思う。
仕様はこんな感じで。
Fibonacciクラス
プロパティ
- count :何番目のフィボナッチ数か
- number :フィボナッチ数
コンストラクタ
- init :単純に初期化するとフィボナッチ数列の最初の2項を 1, 2 にする。
- initWithNumber :フィボナッチ数列の最初の2項を指定して初期化する。
メソッド
- next :値を次に更新する(同時に更新したフィボナッチ数を返す)
クラス定義
Objective-Cでクラスを定義するには2つのファイルを用意する必要がある。
- クラスのプロパティ、変数、メソッドを宣言する「.h」ファイル
- 実際の動作をコーディングする「.m」ファイル
#import <Foundation/Foundation.h>
@interface Fibonacci : NSObject
{
@private
int num1,num2;
}
@property (nonatomic) int number;
@property (nonatomic) int count;
-(id)init;
-(id)initWithNumber:(int)number1 n2:(int)number2;
-(int)next;
@end
ちょっと悩んだのが-(id)initWithNumber:(int)number1 n2:(int)number2;
の部分。
一般的な言語のよくある書き方だと
public static int initWithNumber(int number1,int number2)
みたいになると思うんだけど、objective-cでは”n2”の部分が必要となる。
メソッドに引数が複数必要な場合はこの「ラベル」が必要らしいんだけど、再利用するわけでもなさそうだしイマイチ意味がわからない。
まぁ付けなきゃダメみたいです。
#import "Fibonacci.h"
@implementation Fibonacci
-(id)init{
self = [super init];
if (self) {
num1 = 1;
num2 = 2;
self.count =1;
self.number = 1;
}
return self;
}
-(id)initWithNumber:(int)number1 n2:(int)number2
{
self = self.init;
self.number = number1;
num1 = number1;
num2 = number2;
return self;
}
-(int)next{
if (self.count == 1) {
self.number = num2;
}else{
self.number = num1 + num2;
num1 = num2;
num2 = self.number;
}
self.count++;
return self.number;
}
@end
まず、ヘッダファイルをimportしなきゃダメ。ゼッタイ。
#import "Fibonacci.h"
コンストラクタに該当するinitメソッドでは親クラスのinitを使って初期化して、selfがnilじゃなければ初期化処理。
最後にselfを返す、という流れが鉄則です。
-(id)init{
self = [super init];
if (self) {
//初期化処理
}
return self;
}
そんなこんなでフィボナッチ数を取得するクラスが出来たので、実際に動かして試してみましょう。
Fibonacci *fibo = [[Fibonacci alloc]init];
do{
NSLog(@"%d:%d",fibo.count, fibo.number);
}while (fibo.next < 100);
/*
2013-04-29 11:03:32.859 Euler[30350:303] 1:1
2013-04-29 11:03:32.862 Euler[30350:303] 2:2
2013-04-29 11:03:32.863 Euler[30350:303] 3:3
2013-04-29 11:03:32.865 Euler[30350:303] 4:5
2013-04-29 11:03:32.866 Euler[30350:303] 5:8
2013-04-29 11:03:32.867 Euler[30350:303] 6:13
2013-04-29 11:03:32.868 Euler[30350:303] 7:21
2013-04-29 11:03:32.869 Euler[30350:303] 8:34
2013-04-29 11:03:32.870 Euler[30350:303] 9:55
2013-04-29 11:03:32.871 Euler[30350:303] 10:89
*/
#import "Fibonacci.h"
を忘れないように。
ちゃんと動いてるようなので本題の回答を。
回答
Fibonacci *fibo = [[Fibonacci alloc]init];
int sum = 0;
do{
if (fibo.number % 2 == 0) {
sum = sum + fibo.number;
}
}while (fibo.next < 4000000);
NSLog(@"answer:%d",sum);
//2013-04-29 11:12:31.844 Euler[30420:303] answer:4613732
今回覚えたワザ
do while
do{
//繰り返す処理内容
}while (条件式);
通常のwhileは処理前に条件を評価するが、do-whileは処理後に評価する。
つまりwhileは条件が偽を返したら処理内容はスキップされるのに対して、
do-whileは条件が真でも偽でも一回は処理を行う
おねがい
えらそーに書いてますけどObjective-Cは初心者なので間違ってる所があったら暖かくツッコんでくださいおねがいします。