本講義では 2 通のレポートで評価します。 レポートは A4 の紙を縦に使い、適宜表紙を付けて提出すること。 またプログラムは C 言語で作成しなさい。
範囲外の場合の年の初期値を変更した。これにより、範囲外で年の 計算式を変える必要が無くなった。 同時に、実行例も差し替えた。 但し、変更前の値に対して作成したプログラムを提出しても同等に評価する。
なお、遅れレポートは受け取らない。
和暦のリストを考えるために以下の構造体を考える。
#include "wareki.h"
typedef struct wl {
WAREKI wareki;
struct wl* next;
} WAREKILIST;
なお、この構造体の定義と、作成する関数のプロトタイプ宣言を定義するヘッ ダファイル wareki2.h は後述する。
課題1で作成した関数は変更しない限りそのまま使用してよい。 レポート作成においては、課題1で作成した関数を使用する際には、課題1で作成したことだけを述べ、プログラムの説明は省略してよい。
WAREKI 型の構造体を引数として、西暦に変換し、 SEIREKI 型として返す
SEIREKI toseireki(WAREKI w);
を作成しなさい。
なお、「平成元年1月1日」などありえない日付に関しては、どのように動作し
ても良い。
そして、テストプログラム2-1と結合して正しく動作していることを確認しなさい。
#include <stdio.h>
#include <stdlib.h>
#include "wareki.h"
#include "wareki2.h"
int main(void){
WAREKI w[]={{3,4,5,1},{4,5,6,2},{5,6,7,3},{0}};
WAREKI *i;
for(i=w;i->y!=0;i++){
printwareki(*i);
printf("->");
printseireki(toseireki(*i));
printf("->");
printwareki(towareki(toseireki(*i)));
printf("\n");
}
return 0;
}
大正3年4月5日->西暦1914年4月5日->大正3年4月5日 昭和4年5月6日->西暦1929年5月6日->昭和4年5月6日 平成5年6月7日->西暦1993年6月7日->平成5年6月7日
WAREKILIST の番地を受け取り、線形リストとして和暦を順に表示する
void printwarekilist(WAREKILIST* w, char* sep)
を作成しなさい。
ただし、次の条件を満たすものとする。
そして、テストプログラム2-2と結合して正しく動作していることを確認しなさい。
#include <stdio.h>
#include <stdlib.h>
#include "wareki.h"
#include "warekilist.h"
int main(void){
char sep[]="--";
WAREKILIST w0={0};
WAREKILIST w1={3,4,5,1};
WAREKILIST w2={4,5,6,2};
WAREKILIST w3={5,6,7,3};
w0.next=NULL;
w1.next=&w0;
w2.next=&w1;
w3.next=&w2;
printwarekilist(&w0,sep);
printf("\n");
printwarekilist(&w1,sep);
printf("\n");
printwarekilist(&w2,sep);
printf("\n");
printwarekilist(&w3,sep);
printf("\n");
return 0;
}
大正3年4月5日 昭和4年5月6日--大正3年4月5日 平成5年6月7日--昭和4年5月6日--大正3年4月5日
先頭は空行なのに注意
以下の3つの関数を作りなさい。
WAREKILIST* newnode(void)
WAREKILIST* add(WAREKILIST* p, WAREKI w)
void freelist(WAREKILIST* p)
そして、テストプログラム2-3と結合して正しく動作していることを確認しなさい。
#include <stdio.h>
#include <stdlib.h>
#include "wareki.h"
#include "wareki2.h"
int main(void){
char sep[]="--";
WAREKILIST* p;
WAREKILIST* q;
WAREKI w[]={{3,4,5,1},{4,5,6,2},{5,6,7,3},{0}};
WAREKI *i;
if((p=newnode())==NULL) return 1;
printwarekilist(p,sep);
printf("\n");
for(i=w;i->y!=0;i++){
if((q=add(p,*i))==NULL){
freelist(p);
return 1;
}
printf("追加項目:");
printwareki(q->wareki);
printf(" ");
printwarekilist(p,sep);
printf("\n");
}
freelist(p);
return 0;
}
追加項目:大正3年4月5日 大正3年4月5日 追加項目:昭和4年5月6日 昭和4年5月6日--大正3年4月5日 追加項目:平成5年6月7日 平成5年6月7日--昭和4年5月6日--大正3年4月5日
先頭は空行なのに注意
和暦の線形リストのポインターを受け取り、
和暦と、その間の日数を順に表示する
void printnissulist(WAREKILIST* w, char* sep)
を作成しなさい。
ただし、次の条件を満たすものとする。
そして、テストプログラム2-4と結合して正しく動作していることを確認しなさい。
#include <stdio.h>
#include <stdlib.h>
#include "wareki.h"
#include "wareki2.h"
int main(void){
char sep[]=" -- ";
WAREKI w[]={{3,4,5,1},{4,5,6,2},{5,6,7,3},{0}};
WAREKI *i;
WAREKILIST* p;
WAREKILIST* q;
if((p=newnode())==NULL) return 1;
printwarekilist(p,sep);
printf("\n");
for(i=w;i->y!=0;i++){
if((q=add(p,*i))==NULL){
freelist(p);
return 1;
}
printf("追加項目:");
printwareki(q->wareki);
printf(" ");
printnissulist(p,sep);
printf("\n");
}
freelist(p);
return 0;
}
追加項目:大正3年4月5日 大正3年4月5日 追加項目:昭和4年5月6日 昭和4年5月6日 -- -5510日 -- 大正3年4月5日 追加項目:平成5年6月7日 平成5年6月7日 -- -23408日 -- 昭和4年5月6日 -- -5510日 -- 大正3年4月5日
先頭は空行なのに注意
以下、追加のヘッダファイルを示す。
typedef struct wl {
WAREKI wareki;
struct wl* next;
} WAREKILIST;
SEIREKI toseireki(WAREKI w);
void printwarekilist(WAREKILIST* w, char* sep);
WAREKILIST* newnode(void);
WAREKILIST* add(WAREKILIST* p, WAREKI w);
void freelist(WAREKILIST* p);
void printnissulist(WAREKILIST* w, char* sep);
解答法として、分割コンパイルによる別ファイルにプログラムを書く方 法と、下記のテストプログラムに関数を追記する方法の二通りがあるがどちら でも良い。 プログラムの解説は、自分で作成した関数について行うこと。 こちらで提供したテストプログラムの説明は基本的には不要である。 但し、自分で作成した関数を説明するのに必要な内容には言及すること。
なお、遅れレポートは教員に直接提出してください。 遅れた方が有利にならない範囲内で採点します。 遅れレポートの最終期限は7月26日18:10(授業開始時)です。
和暦のカレンダーの関数を作成する
始めに西暦のデータ型 SEIREKI を下記のように定める。
typedef struct {
int y,m,d;
}SEIREKI;
これを表示する void printseireki(SEIREKI s) を作成せよ。 そして、下記のプログラムと結合し、実行結果を報告せよ。
#include <stdio.h>
#include "wareki.h"
int main(void){
SEIREKI s[]={{1858,11,17},
{1868,1,25},
{1912,7,29},
{1912,7,30},
{0}};
SEIREKI *p;
for(p=s; p->y!=0; p++){
printseireki(*p);
printf("\n");
}
return 0;
}
西暦1858年11月17日 西暦1868年1月25日 西暦1912年7月29日 西暦1912年7月30日
和暦を扱うデータ型WAREKIを次のように定義する。
typedef struct {
int y,m,d;
int index;
}WAREKI;
このうち、index は下記の配列 char* gengou[] の要素を指す添字である (グレゴリオ歴は明治6年より採用なので、下記の範囲内では月日は西暦と和暦 で一致する) 。
extern char* gengou[];
char* gengou[]={"範囲外","大正","昭和","平成",NULL};
この時、和暦を表示する関数 void printwareki(WAREKI g) を作成せよ。 但し、和暦では1年は元年と表示すること。 そして、下記のプログラムとさらに課題末尾に掲載している補助プログラム と結合し、実行結果を報告せよ。
#include <stdio.h>
#include "wareki.h"
int main(void){
WAREKI w[]={{1,10,25,1},
{2,1,1,2},
{1,12,31,2},
{30,7,30,3},
{0}};
WAREKI *p;
for(p=w; p->y!=0; p++){
printwareki(*p);
printf("\n");
}
return 0;
}
大正元年10月25日 昭和2年1月1日 昭和元年12月31日 平成30年7月30日
修正ユリウス日とは1858年11月17日から数えた日数である。 これを計算する計算式は次で与えられる
この時、西暦(グレゴリオ歴)から修正ユリウス日を計算する関数 int mjd(SEIREKI s) を作成せよ。 但し、和暦では1年は元年と表示すること。 なお、修正ユリウス日から西暦を計算する関数 SEIREKI invmjd(int mjd)は 課題末尾に掲載している補助プログラムに示した。 そして、下記のプログラムとさらに問題1で作成したプログラムと 課題末尾に掲載している補助プログラム とを結合し、実行結果を報告せよ。
#include <stdio.h>
#include "wareki.h"
int main(void){
SEIREKI s[]={{1858,11,17},
{1868,1,25},
{1912,7,29},
{1912,7,30},
{0}};
SEIREKI s1;
SEIREKI *p;
int i,n;
for(p=s; p->y!=0; p++){
printseireki(*p);
n=mjd(*p);
printf("の修正ユリウス日は%dで、逆変換すると",n);
printseireki(invmjd(n));
printf("となる\n");
}
for(i=0;i<100000; i++){
s1=invmjd(i);
if(i!=mjd(s1)){
printseireki(s1);
printf("\n");
}
}
return 0;
}
西暦1858年11月17日の修正ユリウス日は0で、逆変換すると西暦1858年11月17日となる 西暦1868年1月25日の修正ユリウス日は3356で、逆変換すると西暦1868年1月25日となる 西暦1912年7月29日の修正ユリウス日は19612で、逆変換すると西暦1912年7月29日となる 西暦1912年7月30日の修正ユリウス日は19613で、逆変換すると西暦1912年7月30日となる
西暦から和暦に変換する関数 WAREKI towareki(SEIREKI s) を作成せよ。 但し、補助プログラムには以下の配列が定義されているとする。
extern char* gengou[];
extern SEIREKI gannen[];
char* gengou[]={"範囲外","大正","昭和","平成",NULL};
SEIREKI gannen[]={{1,0,0},
{1912,7,30},
{1926,12,25},
{1989,1,8},
{-1}};
2016/6/14 範囲外の場合の年の初期値を変更した。これにより、範囲外で年の 計算式を変える必要が無くなった。 同時に、実行例も差し替えた。 但し、変更前の値に対して作成したプログラムを提出しても同等に評価する。
この時、西暦(グレゴリオ歴)を和暦に変換する関数 WAREKI towareki(SEIREKI s) を作成せよ。 そして、下記のプログラムとさらに問題1,2,3で作成したプログラムと 課題末尾に掲載している補助プログラム とを結合し、実行結果を報告せよ。
#include <stdio.h>
#include "wareki.h"
int main(void){
SEIREKI range[]={{1912,7,29},
{1912,8,1},
{1926,12,24},
{1927,1,1},
{1988,12,31},
{1989,1,8},
{0}};
int i;
SEIREKI s;
SEIREKI *p;
for(p=range; p->y!=0; p+=2){
for(i=mjd(*p); i<=mjd(*(p+1)); i++){
s=invmjd(i);
printseireki(s);
printf(" = ");
printwareki(towareki(s));
printf("\n");
}
}
return 0;
}
西暦1912年7月29日 = 範囲外1912年7月29日 西暦1912年7月30日 = 大正元年7月30日 西暦1912年7月31日 = 大正元年7月31日 西暦1912年8月1日 = 大正元年8月1日 西暦1926年12月24日 = 大正15年12月24日 西暦1926年12月25日 = 昭和元年12月25日 西暦1926年12月26日 = 昭和元年12月26日 西暦1926年12月27日 = 昭和元年12月27日 西暦1926年12月28日 = 昭和元年12月28日 西暦1926年12月29日 = 昭和元年12月29日 西暦1926年12月30日 = 昭和元年12月30日 西暦1926年12月31日 = 昭和元年12月31日 西暦1927年1月1日 = 昭和2年1月1日 西暦1988年12月31日 = 昭和63年12月31日 西暦1989年1月1日 = 昭和64年1月1日 西暦1989年1月2日 = 昭和64年1月2日 西暦1989年1月3日 = 昭和64年1月3日 西暦1989年1月4日 = 昭和64年1月4日 西暦1989年1月5日 = 昭和64年1月5日 西暦1989年1月6日 = 昭和64年1月6日 西暦1989年1月7日 = 昭和64年1月7日 西暦1989年1月8日 = 平成元年1月8日
以下、ヘッダファイルと補助プログラムを示す。
typedef struct {
int y,m,d;
}SEIREKI;
typedef struct {
int y,m,d;
int index;
}WAREKI;
extern char* gengou[];
extern SEIREKI gannen[];
void printseireki(SEIREKI s);
void printwareki(WAREKI w);
int mjd(SEIREKI s);
SEIREKI invmjd(int mjd);
WAREKI towareki(SEIREKI s);
#include <stdlib.h>
#include "wareki.h"
char* gengou[]={"範囲外","大正","昭和","平成",NULL};
SEIREKI gannen[]={{1,0,0},
{1912,7,30},
{1926,12,25},
{1989,1,8},
{-1}};
SEIREKI invmjd(int mjd){
SEIREKI result;
int n=mjd+678881;
int a=4*n+3+4*(int)(0.75*(int)(((double)4*n+1)/146097+1));
int b=5*(int)((double)(a%1461)/4)+2;
result.m = (b/153+14)%12+1;
result.y = a/1461+((result.m<3)?1:0);
result.d = b%153/5+1;
return result;
}