質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Q&A

4回答

4246閲覧

閏年判定のプログラムを採点してください

退会済みユーザー

退会済みユーザー

総合スコア0

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

1グッド

3クリップ

投稿2016/03/12 09:27

編集2016/03/12 10:09

Rubyで閏年判定のアルゴリズムを書きました。

命名やクラス化、アルゴリズムの観点から良いコードか悪いコードか採点して欲しいです。

ruby

1class Leap 2 def checkYear?(n) 3 if n%400 == 0 4 return true 5 end 6 7 if n%4 == 0 && n%100 == 0 8 return false 9 end 10 11 if n%4 == 0 12 return true 13 end 14 15 return false 16 end 17end 18 19leap = Leap.new 20p "閏年" if leap.checkYear?(gets.to_i)

また、自分だったらこういう風に書くというのを教えていただきたいです。できればアドバイス等も頂きたいです。

daikitakaya👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

私が書く場合を示します。
(でも、そもそも うるう年判定なら、ruby にすでにメソッドがあるので、自分では書くことは無いとおもいますが)

leap.rb

ruby

1require 'date' 2 3class Leap 4 def self.check?(year) 5 (year % 400 == 0) || (year % 100 != 0 && year % 4 == 0) 6 end 7end 8 9TESTS = { 10 1998 => false, 11 1999 => false, 12 2000 => true, 13 2001 => false, 14 2004 => true, 15 2008 => true, 16 2100 => false 17}.freeze 18 19TESTS.each do |year, result| 20 actual = Leap.check?(year) 21 puts "ERROR: #{year} -> #{actual}" if actual != result 22end 23 24 # ruby の Date クラスのうるう年判定メソッドと比較する 25(1900..2400).each do |year| 26 result = Leap.check?(year) 27 result2 = Date.leap?(year) 28 puts "ERROR: #{year} Date.leap?() != Leap.check?()" if result != result2 29end

変更したのは次の点です。

  1. メソッド名を変更しました。

--> まずは checkYear? でなく check_year? に変更しましたが、さらに check? にしました。
(本当は、クラス名も変えて、それに合わせてメソッドもさらに別のものに変えたいところですが ...)
2. インスタンスに依存した処理ではないので、クラス・メソッドにしました。
3. 判定を 条件文1つにまとめました。
4. キー入力して試すのでなく、プログラム内部で主な年について試すようにしました。
(ここではさらに、ruby の Data.leap? との動作チェックもしてみました)

参考情報:

投稿2016/03/12 11:29

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

raccy

2016/03/12 11:33

Date.leap?なんてものがあったとは・・・
guest

0

アルゴリズムの観点からと言うことなので、その観点だけでコメントします。
約3/4のケースは閏年で無いので、そのケースを最初に判定すべき。
まあ、このケースだと微々たる差ですが、一般論としては、少数ケースの中の場合分けにコストが掛かる場合は効いてきます。

Ruby

1def checkYear?(n) 2 if n%4 != 0 3 return false 4 end 5 6 if n%400 == 0 7 return true 8 end 9 10 if n%100 == 0 11 return false 12 end 13 14 return true 15end

投稿2016/03/12 11:11

otn

総合スコア84551

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

majiponi

2016/03/12 12:25

その考え方に立つなら、4で割り切れる場合でも、先に100で割り切れないから閏年に確定、とするほうがもっと速くなりますよね?
otn

2016/03/12 16:16

ああ、確かにそうですね。指摘ありがとうございます。
guest

0

閏年の条件を忘れてしまった!
と言うときは、Dateを使うという方法もあります。

Ruby

1require 'date' 2def check_leap_year(year) 3 Date.valid_date?(year, 2, 29, Date::GREGORIAN) 4end

アルゴリズムを考える勉強にはなりませんが、便利なライブラリは積極的に使うと楽ができます。

投稿2016/03/12 11:25

raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Q1. クラスに入れてある理由を説明してください。
(単純な関数ではダメですか?)

Q2. 400で割り切れる数は、100でも4でも割り切れますよね?
(無駄な判定がある)

Q3. 2001年を引数にした場合の結果は何ですか?
(漏れがある)

Ruby

1def isLeapYear(year) 2 if year%400 == 0 3 return true 4 end 5 6 if year%100 == 0 7 return false 8 end 9 10 if year%4 == 0 11 return true 12 end 13 14 return false 15end

投稿2016/03/12 09:35

編集2016/03/12 09:50
majiponi

総合スコア1720

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2016/03/12 09:41

ご回答ありがとうございます。 Q1につて 単純な関数でもいいのですが、今後パッケージ化などした際に扱いやすいと思ったのでクラス化しました。 Q2について コード修正するので確認お願いします。 Q3について 何も帰ってきませんが、問題があるのでしょうか? よろしくお願いします。
majiponi

2016/03/12 09:48

Q1.補足 クラスにまとめるということには、オブジェクトと何かしらの関係がある、ということです。例えば時刻、日付を扱うオブジェクトに関するクラスでしたら、閏年の判定は意味があります。ですが、ただ単に閏年か判定するだけのオブジェクトを作るクラスって、必要ですか? Q2.補足 あくまで例示です。100で割り切れたら4で割り切れることは省略して書いてます。 Q3.補足 例えば、2000年でしたらtrueが返ってきて、1900年でしたらfalseが返ってきますよね。2016年ならtrueが返ってきて、2015年なら…あれ、何も返ってきませんね? そういうことです。falseという値を返す意味がある、ということです。呼び出し側ではその年が閏年(true)か?という判定法以外に、平年(false)か?という判定法も考えられますから。
退会済みユーザー

退会済みユーザー

2016/03/12 10:08

返信ありがとうございます。 Q1について なるほど。つまり現状だと閏年を返す関数のみしかないので、クラス化する必要はないということですか?今後このクラスに様々な関数が作られ、閏年判定に関係するならばクラス化は有効だということですか? Q2について コード修正して思ったのですが、閏年はそもそも4と100で割り切れ、且つ400でも割り切れる時を示すと思います。確かに400で割切れるなら4,100の計算は無駄になります。 しかし、コードを他者が見た時に、このif文ではどういう処理なのか、どういう意図のコードなのか分からない気がするのですが。いかがでしょう? Q3について おっしゃる通りでした。すべての条件式に該当しない場合、falseを返すようにしました。
majiponi

2016/03/12 12:23

Q2補足の補足 なら、コメントできちんと書けばいいのです。(私は関数名で何をやっているか分かるので、コメントで補足する必要すらないと思いますが) そもそも、例外中の例外から判定しているからそうなるのであって、他の方が指摘するように、原則(通常の平年)、例外の原則(4で割り切れて100で割り切れない)、例外の例外(100で割り切れて400で割り切れない)、例外の例外の例外、の順に書けば特に問題ありませんよね?
退会済みユーザー

退会済みユーザー

2016/03/12 13:27

返信ありがとうございます。 確かに確率の大きい事象から判定するのが良さそうですね。 今後気をつけます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問