ツェラーの公式

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
みけCAT

ツェラーの公式

#1

投稿記事 by みけCAT » 14年前

ツェラーの公式を使って、大学入試センター試験の記入日までの
残り日数を表示するプログラムを作ってみました。
ほとんどうまくいったのですが、西暦3700年くらいから誤動作し始めます。
原因がわかる方がいらっしゃいましたらよろしくお願いします。
デバッグに使ったプログラムはこれです。
#include <stdio.h>

int dnssmade(int,int,int);

int main(void) {
    int ml[12]={31,28,31,30,31,30,31,31,30,31,30,31};
    int year,month,date;
    int yearto;
    int zenkai=0;
    int konkai;
    printf("何年からデバッグしますか?");
    scanf("%d",&year);
    printf("何年までデバッグしますか?");
    scanf("%d",&yearto);
    month=1;date=1;
    while(year<=yearto) {
        konkai=dnssmade(year,month,date);
        if(zenkai!=0 && konkai!=zenkai-1) {
            printf("%d年%d月%d日 今回:あと%d日 前回:あと%d日\n",
                year,month,date,konkai,zenkai);
        }
        zenkai=konkai;
        date++;
        if(date>ml[month-1]) {
            date=1;
            month++;
            if(month==2) {
                ml[1]=28;
                if(year%4==0 && year%100!=0)ml[1]=29;
                if(year%400==0)ml[1]=29;
            }
            if(month>12) {
                month=1;
                year++;
            }
        }
    }
    printf("デバッグが終了しました。\n");
    return 0;
}

int dnssmade(int year,int month,int date) {
    static int ml[12]={31,28,31,30,31,30,31,31,30,31,30,31};
    int dayofweek,ok,g,no,i;
    int y,m;
    if(month<=2) {
        y=year-1;
        m=month+12;
    } else {
        y=year;
        m=month;
    }
    dayofweek=(y%100+(y%100)/4+y/400-2*(y/100)+13*(m+1)/5+date)%7;
    if(dayofweek==0)dayofweek=7;
    ml[1]=28;
    if(year%4==0 && year%100!=0)ml[1]=29;
    if(year%400==0)ml[1]=29;
    ok=0;
    if(month==1) {
        g=dayofweek-date+1;
        while(g<1)g=g+7;
        no=7-g+15-date;
        if(no==-1)no=0;
        if(no>=0)ok=1;
    }
    if(ok==0) {
        no=ml[month-1]-date+1;
        for(i=month;i<=11;i++)no=no+ml;
        g=(dayofweek-1+no)%7+1;
        no=no+7-g+14;
    }
    return no;
}

出力例です。

何年からデバッグしますか?2000
何年までデバッグしますか?4000
3700年12月26日 今回:あと27日 前回:あと21日
3701年1月1日 今回:あと14日 前回:あと22日
3800年12月28日 今回:あと27日 前回:あと21日
3801年1月1日 今回:あと16日 前回:あと24日
3801年12月27日 今回:あと27日 前回:あと21日
3802年1月1日 今回:あと15日 前回:あと23日
3802年12月26日 今回:あと27日 前回:あと21日
3803年1月1日 今回:あと14日 前回:あと22日
3900年12月30日 今回:あと27日 前回:あと21日
3901年1月1日 今回:あと18日 前回:あと26日
3901年12月29日 今回:あと27日 前回:あと21日
3902年1月1日 今回:あと17日 前回:あと25日
3902年12月28日 今回:あと27日 前回:あと21日
3903年1月1日 今回:あと16日 前回:あと24日
3903年12月27日 今回:あと27日 前回:あと21日
3904年1月1日 今回:あと15日 前回:あと23日
4000年12月31日 今回:あと27日 前回:あと21日
デバッグが終了しました。

参考にしたサイトはこれです。
ツェラーの公式
http://www.geocities.jp/etctools0/cobol.html
大学入試センター試験
http://bit.ly/8wmFb6

めるぽん

Re:ツェラーの公式

#2

投稿記事 by めるぽん » 14年前

dayofweek=(y%100+(y%100)/4+y/400-2*(y/100)+13*(m+1)/5+date)%7;

に、y=3700, m=12, date=26 を入れれば分かりますが、

(3700%100+(3700%100)/4+3700/400-2*(3700/100)+13*(12+1)/5+26)%7
(0+0+9-2*(37)+13*(13)/5+26)%7
(9-74+33+26)%7
(-6)%7

となります。負の値に対する mod は C89 では規定されていなかったと思いますが、大抵の環境では -6 になります。
多分 1 になるのが期待した動作だと思うので、
n=y%100+(y%100)/4+y/400-2*(y/100)+13*(m+1)/5+date;
while(n<0)n+=7;
dayofweek=n%7;
とすれば、曜日の計算は正常に動作しそうです(while とか使うのではなく、もっとまともに計算する方法もあると思いますが)。

みけCAT

Re:ツェラーの公式

#3

投稿記事 by みけCAT » 14年前

携帯からなので確認できないのですが
if(n<0)n+=(-n)/7*7+7;
dayofweek=n%7;
のような感じですか?

みけCAT

Re:ツェラーの公式

#4

投稿記事 by みけCAT » 14年前

No.64084の方法で西暦1年以降は正常に動作しました。
西暦0年からは異常でしたが、これは仕様ということにします。
ありがとうございました。

めるぽん

Re:ツェラーの公式

#5

投稿記事 by めるぽん » 14年前

ツェラーの公式は、グレゴリオ歴が制定された 1582年10月15日から有効なので、それ以前は範囲外エラーとして出すべきなのでは無いでしょうか。

初級者

Re:ツェラーの公式

#6

投稿記事 by 初級者 » 14年前

ていうか、西暦1年にはセンター試験はなかったわけでw
そんな年について計算することには、何の意味もありません。わかりますよね?


ただやみくもに公式を当てはめるのではなく、
「センター試験制度開始以降の年を有効とする」というように、
「実態に即した仕様」を考えては?


画像

閉鎖

“C言語何でも質問掲示板” へ戻る