• ベストアンサー

うるう年判定のアルゴリズム

javaでうるう年判定のプログラムを作成しています。 プログラム自体はサーバにアップするときに実行結果が正しいかどうかテストされます。 仕様としては、 1.時間に関するAPIなどは一切使わずに完全に自作 2.入力される値はLong型の"秒"数(APIで提供されているのはミリ秒ですが) 3.60537895631062456(Long値) などの入力値に対して、年/月/日 (曜日) 時:分:秒 yday=元旦からの経過日数 を出力 最初は以下の関数を使用してループをかけていたのですが、仕様3の入力値に対して50秒近くかかってしまい、上手くいきませんでした。 public static int isLeap(int year){ if(year%4==0 && (year%100!=0 || year%400==0)) return 1; return 0; } 問題点はループ回数が多いことで、作る時点で分かってはいたのですが、ここまで遅くなるとは思っても見ませんでした。 これを使わない方法としては、一回だけうるう年(=n)を見つけ、その後は「(n+4)との比較+100で割り切れず400で割り切れる場合は別」という処理を行うことによって、処理時間を30秒付近にまで短縮することができたのですが、どうも10~15秒以内で終わらせなければテストにパスすることができないようです。 なんとか色々考えてはみたものの、上手いアルゴリズムは思いつきませんでした。 うるう年を処理するための"高速な"アルゴリズムはないのでしょうか。 お知恵を貸してください。よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • don_go
  • ベストアンサー率31% (336/1059)
回答No.2

>3.60537895631062456(Long値) などの入力値に対して ↑は何の値でしょうか? (特定の年の元旦からの経過秒数?または任意の年月日?) 起点の年月日が既知であれば、それがうるう年か否かはすぐ わかるはずですが? >最初は以下の関数を使用してループをかけていたの >ですが、仕様3の入力値に対して50秒近くかかって >しまい、上手くいきませんでした。 > >public static int isLeap(int year){ >if(year%4==0 && (year%100!=0 || year%400==0)) >return 1; >return 0; >} 上記にはループなどありませんが、どういったループを かけたのがわからないと、どこが悪かったのか確認のしよう が無いと思いますが?

hydrangeas0722
質問者

お礼

1970年1月1日0:0:0 からの経過時間(秒)です。 それに対し、時,分,秒を求めた後、経過年数を求めようとしていました。 この問題に関してはJAVAのスレッドで解決していただきました。 真剣に考えて頂き、本当にありがとうございました。 スレッド違いのため、管理者に削除依頼を行いました。

その他の回答 (1)

  • amru05
  • ベストアンサー率63% (33/52)
回答No.1

JAVAの質問の方で答えておきましたが、 400年を単位にして計算して、残りを詳細に調べれば そんなに多くのループにはならないので早くなると思います。

hydrangeas0722
質問者

お礼

ありがとうございました。 スレッドを間違えて申し訳ありません。 管理者に削除依頼をしておきました。

関連するQ&A

  • うるう年判定のアルゴリズム

    javaでうるう年判定のプログラムを作成しています。 プログラム自体はサーバにアップするときに実行結果が正しいかどうかテストされます。 仕様としては、 1.時間に関するAPIなどは一切使わずに完全に自作 2.入力される値はLong型の"秒"数(APIで提供されているのはミリ秒ですが) 3.60537895631062456L などの入力値に対して、年/月/日 (曜日) 時:分:秒 yday=元旦からの経過日数 を出力 最初は以下の関数を使用してループをかけていたのですが、仕様3の入力値に対して50秒近くかかってしまい、上手くいきませんでした。 public static int isLeap(int year){ if(year%4==0 && (year%100!=0 || year%400==0)) return 1; return 0; } 問題点はループ回数が多いことで、作る時点で分かってはいたのですが、ここまで遅くなるとは思っても見ませんでした。 これを使わない方法としては、一回だけうるう年(=n)を見つけ、その後は「(n+4)との比較+100で割り切れず400で割り切れる場合は別」という処理を行うことによって、処理時間を30秒付近にまで短縮することができたのですが、どうも10~15秒以内で終わらせなければテストにパスすることができないようです。 なんとか色々考えてはみたものの、上手いアルゴリズムは思いつきませんでした。 うるう年を処理するための"高速な"アルゴリズムはないのでしょうか。 お知恵を貸してください。よろしくお願いします。

    • ベストアンサー
    • Java
  • 閏年のプログラム

    C言語(閏年)の質問です。 任意の範囲の年から閏年の表示とその数をカウントして次の実行結果のように表示するプログラムの作成で途中まではわかって修正・追加する箇所があったら一緒に教えてください。(ここでは2つの年をmain関数内で入力し、その範囲の西暦を引数とする関数checkYearを使用するものとする。int型の関数checkYearは、引数に西暦をとり、その西暦が閏年であれば、1を返し、閏年でない場合は0を返す。) なお、閏年の判定方法は以下のとおりである。 条件1 西暦年が4で割り切れる年は閏年である 条件2 条件1を満たしていても、西暦年が100で割り切れるときは閏年でない 条件3 条件2を満たしていても、西暦年が400で割り切れるならば閏年である 実行例1 西暦を入力:2000 西暦を入力:2009 2000年 2004年 2008年 閏年は3回あります。 実行例2 西暦を入力:2100 西暦を入力:2000 2000年 2004年 2008年 2012年 2016年 2020年 (省略) 2096年 閏年は25回あります。 実行例3 西暦を入力:2090 西暦を入力:2110 2092年 2096年 2104年 2108年 閏年は4回あります。 #include <iostream> bool checkYear(int year); int main() { int year; int year2; printf("西暦を入力:"); scanf("%d",year); printf("西暦を入力:"); scanf("%d",year2); int count = 0; for (int i = year; i < year2; i++) { if (checkYear(i)) { printf("%d年\n"); count++; } } printf("閏年は%d回です。\n"); return 0; } bool checkYear(int year) { return (((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0); }

  • うるう年判定

    こんにちは。今回も宜しくお願いします<(_ _)> 画面から入力された日付(生年月日)の妥当性をチェックしたいのですが、それにはまずクラス(API)をわかっていなくてはいけないと思い、お試しで作ったものが、私の想像していた通りに動きません。 import java.util.*; public class Test {  public static void main(String[] args) {   int year;   int month;   int day;   GregorianCalendar g = new GregorianCalendar();   year = g.get( Calendar.YEAR );   month = g.get( Calendar.JUNE );   day = g.get( Calendar.DATE );   System.out.println("year = " + year);   System.out.println("month = " + month);   System.out.println("day = " + day);   } } 上記のソースを実行すると、 C:\WINDOWS\デスクトップ\カレンダ>java Test year = 2003 month = 3 day = 3 となります。月の指定はCalendar.JUNEとしているのに、どうして3と表示されるのでしょうか? あともう一つ質問なのですが、GregorianCalendarに自分の好きな年月を与えたいのですが、 g.get( 1980 ); とすると実行時にArrayIndexOutOfBoundsExceptionのエラーがでます。 GregorianCalendarを使って任意の年月を渡すことは無理なんでしょうか? 私が最初考えたのが、画面から入力された値をそのままGregorianCarendarに渡して、もしもその時にエラーがでたらそれは妥当ではなかった値(閏年じゃないのに2月29日と入力したり、とか)として、画面にて再入力を促すメッセージをだそうと思っていたのですが、この考え方はどこか変でしょうか? お手数お掛けいたしますが、宜しくお願い致します<(_ _)>

    • ベストアンサー
    • Java
  • C++でうるう年判定のプログラムを作りたいのですが

    C++でうるう年判定のプログラムが作りたいのですが・・・ #include <iostream> using namespace std; int main() { return 0; } 問題のこの下の部分の内容が書けません 変数をa % 4という計算と%100と%400をしなければいけないことはわかっています。この式の入れ方がわかりませんif文だとは思っているのですが 表示は「<<a<<"はうるう年です";」と「<<a<<"はうるう年ではありません";」という判定を表示したいです。

  • うるう年かどうかを計算するプログラミング

    西暦何年かを入力し、その年がうるう年かそうでないかを 計算するプログラムを作っています。 #include <iostream> using namespace std; int main() { int toshi; cout <<"西暦を入力してください"; cin>>toshi; if (toshi%4==0) {if (toshi%100==0) {if (toshi%400==0) {cout<<toshi<<"年はうるう年です。";} else {cout<<toshi<<"年は非うるう年です。";} else {cout<<toshi<<"年は非うるう年です。";} else {cout<<toshi<<"年は非うるう年です。";}}} return EXIT_SUCCESS; } これを入力したのですが エラーが2つでてしまいます。 どこがちがうのでしょうか?

  • 2004年の前のうるう年をjavaで表せが出来ませ

    大学の講義で出題せれたのですが、javaでそれぞれ1901年、2004年、2007年、2009年の前のうるう年を表示しろということで、うるう年の検索、判定のプログラムまでは組めたのですが、前の年ということで、うるう年である2004年で表示さなくてはいけないのが1996年なのですが、どうしても2004年と表示されてしまいます。 色々と調べてみたのですが分からず、初めての投稿をさせていただきました。 どう組めば良いか教えてください。下が組んだプログラムです。 public static int preleap(int n){ if((n%4 == 0) & (n%100 != 0) ||n%400 == 0){ return n; }else{ return preleap(n-1); } }

    • ベストアンサー
    • Java
  • アルゴリズムの流れ図

    いつもお世話になってます。アルゴリズムの流れ図の中でいくつかどう処理されているのか分からない箇所がありますので、どなたか教えて頂きたいです。 (1)ループの中で、値が0とかマイナスになるときは増分にあたる所はやらないでいいのですか。 (2)入力文字(入力位置+2)→文字数と書いてあって、その後に文字数-1→文字数ってなっている時、入力文字(入力位置+2)が5(4)だったら文字数に入る値は何になりますか。またそのアルゴリズムの書いてある参考書の隣のページのアルゴリズムの様子が書いてあるのから察すると文字数=4みたいですが、じゃあなんで入力文字(入力位置+2)→文字数を入力位置+2→文字数にしないのですか。 (3)定義済み処理(サブルーチン)Xの中にまたサブルーチンXが入っているときはその値を持ってまた最初に戻ればいいんですか。アルゴリズムの様子の所に書いてある入口、出口とはなんですか。 以上1つでも構いませんので宜しくお願いします。

  • C言語 関数問題

    西暦年yearを引数として受け取り,閏年かどうかの判定結果を戻り値として返す関数leap_year()を作成せよ. ただし,leap_year()は,閏年の場合は1を返し,そうでない場合は0を戻り値として返すものとする. 提出するプログラムは,関数leap_year()だけでなく,メイン関数main()も含む下記プログラムを完成させる形で作成する #include <stdio.h> /* ここに関数leap_year()のプロトタイプ宣言を記述する */ int main() { int i, year[3]; for (i=0; i<3; i++) { printf("西暦年を入力してください"); scanf("%d", &year[i]); if (leap_year(year[i]) == 1) { printf("閏年です.\n"); } else { printf("閏年ではありません.\n"); } } } /* ここに関数leap_year()を定義する */

  • 西暦・月からカレンダーを表示

    問題文 西暦・月を入力してカレンダーを表示するプログラムを作成せよ。 プログラム全体のことを考える。プログラムの流れとしては、つぎのようになるであろう。  (1)変数の宣言: プログラムの中で使う変数や配列等をすべてここに集めておく。          (2)入力: キーボードから、西暦年の値を読み取る ← scanf( ) 関数  1月から12月まで、以下を繰り返す。  (3)カレンダーの年・月の表示: (例えば、2008年1月 と表示)  (4)各曜日名の表示: 「日 月 火 水 木 金 土」と表示  (5)月の日数の算出: 月の最後の日を計算しておく。(*1~12月以外では誤りとすること)  (6)曜日の算出: 月の初めの日(ついたち)の曜日をツェラー公式で計算しておく。  (7)空列の表示: ついたちの前の空白部分を表示する ← for文 を利用。  (8)各日の表示: 月の各日を順に表示していく ← for文を利用          (土曜の後に改行を入れる) #include <stdio.h> int leapYear(int year) { if (year%400==0||(year%4==0 && year%100!=0)) { return 1; } else { return 0; } } int main(void) { int d,year,m,i; int day[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; /*1~12月までの各月の日数*/ printf("西暦を入力してください:"); scanf("%d",&year); printf("月を入力してください:"); scanf("%d",&m); if(m!=1 & m!=2 & m!=3 & m!=4 & m!=5 & m!=6 & m!=7 & m!=8 & m!=9 & m!=10 & m!=11 & m!=12)/*1~12月以外で日数を出そうとした場合*/ { printf("入力が誤っています。やりなおしてください。\n"); } else{ if (leapYear(year)==1)/*閏年の場合*/ { printf("%d年は閏年です。\n",year); day[1] +=1; } else/*閏年でない場合*/ { printf("%d年は閏年ではありません。\n",year); } i = (year+year/4 -year/100 +year/400 + ( 13*m+8 )/5 + 1) % 7; /*西暦~年・1~12月の1日の曜日について考える*/ printf("日 月 火 水 木 金 土\n"); (7)・・・ (8)・・・ } return 0; } 手順に沿ってやっていく課題なのですが(7)、(8)の部分の表現の仕方が良く分かりません。(求めた月の日数をカレンダー形式に表示する方法・1日の前に空白を入れる等) 過去の質問も見たのですが、いまいち理解できず・・・orz どなたかご教授お願いできないでしょうか・・・。

  • アルゴリズムの名前を教えてください

    16ビットのデータが、たとえば1000個、配列で与えられているとします。 unsigned short data[1000]; このデータをしらべて、重複するものを除いて何種類の値があるかを数える場合、一番素朴な方法だと、次のようにやると思います。 int i, j; int count = 0; for(i = 0; i < 1000; i++) {  for(j = 0; j < i; j++) {   if(data[j] == data[i]) {    break;   }  }  if(i == j) {   count++;  } } この方法だと、2重のループがあって処理に時間がかかります。そこで、メモリに余裕があれば内側のループをやめて、 int i; int count = 0; int flag[0x10000]; int n; for(i = 0; i < 0x10000; i++) {  flag[i] = 0; } count = 0; for(i = 0; i < 1000; i++) {  n = data[i];  if(flag[n] == 0) {   flag[n] = 1;   count++;  } } これだと、2重のループを使うものよりは速くなりますが、データが1000個しかないのに、65536個のflagをクリアするのに時間がかかり、今ひとつです。 ところが、次のような賢い方法があり、2重のループも配列のクリアも無くすことができます。 int i; int count = 0; unsigned short flag[0x10000]; unsigned short link[0x10000]; int n; for(i = 0; i < 1000; i++) {  n = data[i];  if(flag[n] >= count || link[flag[n]] != n) {   flag[n] = count;   link[count] = n;   count++;  } } 私がこのアルゴリズムを知ったのはかなり昔なので、どこで知ったのか思い出せないのですが、これほど賢いアルゴリズムだから何か名前がついていると思うのですが、それがわかりません。 名前がわからないので、人に頼んだりする時、上のような長い説明をしなくてはなりませんが、名前がわかっていれば「??法でやっといて」、と言えばいいのですけど。

専門家に質問してみよう