コグノスケ


2009年 11月 3日

Automake の不細工な出力

最近は Makefile を自作せずに、GNU Toolchain の勉強も兼ねて GNU Automake を使って Makefile を生成しています。大したプログラムでもないのに ./configure とやるのはめんどくさいけど…。

Automake で作った Makefile はコマンドの実行履歴が大量に出ます。コンパイラに大量のオプションを渡すのと、そのオプションを全てログとして出力するためです。そのせいでコンパイラの警告やエラーがすっ飛んでいって消えてしまいます。

大量のログを見直すのはつらいです。いちいちスクロールバックしたり、パイプしてページャで見なければならないので、非常に面倒です。

Linux の簡素な出力

この点優秀なのが Linux Kernel 2.6 のビルドスクリプトです。単純に make とすると簡潔なログ、make V=1 とすると詳細なログが出ます。

Linux の make は以下のようなログが出ます。どのファイルに何をしている(CC, LD, CHK など)か?だけが表示されます。

Linux Kernel 2.6 の make
$ make
scripts/kconfig/conf -s arch/x86/Kconfig
  CHK     include/linux/version.h
  UPD     include/linux/version.h
(略)
  UPD     include/linux/compile.h
  CC      init/version.o
...

同じ部分の詳細出力(make V=1)は以下のようになります。

Linux Kernel 2.6 の make V=1(80文字折り返し)
$ make V=1
make -f /home/katsuhiro/usr/src/linux-2.6.30/Makefile silentoldconfig
make -f scripts/Makefile.build obj=scripts/basic
mkdir -p include/linux include/config
make -f scripts/Makefile.build obj=scripts/kconfig silentoldconfig
  gcc  -o scripts/kconfig/conf scripts/kconfig/conf.o scripts/kconfig/zconf.tab.
  o -lncurses
scripts/kconfig/conf -s arch/x86/Kconfig
rm -f include/config/kernel.release
echo 2.6.30 > include/config/kernel.release
set -e; : '  CHK     include/linux/version.h'; mkdir -p include/linux/;        (
echo \#define LINUX_VERSION_CODE 132638; echo '#define KERNEL_VERSION(a,b,c) ((
(a) << 16) + ((b) << 8) + (c))';) < /home/katsuhiro/usr/src/linux-2.6.30/Makefil
e > include/linux/version.h.tmp; if [ -r include/linux/version.h ] && cmp -s inc
lude/linux/version.h include/linux/version.h.tmp; then rm -f include/linux/versi
 on.h.tmp; else : '  UPD     include/linux/version.h'; mv -f include/linux/versi
 on.h.tmp include/linux/version.h; fi
(略)
  UPD     include/linux/compile.h
  gcc -Wp,-MD,init/.version.o.d  -nostdinc -isystem /usr/lib/gcc/i486-linux-gnu/
4.3.2/include -Iinclude  -I/home/katsuhiro/usr/src/linux-2.6.30/arch/x86/include
 -include include/linux/autoconf.h -D__KERNEL__ -Wall -Wundef -Wstrict-prototype
s -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-decl
aration -Os -m32 -msoft-float -mregparm=3 -freg-struct-return -mpreferred-stack-
boundary=2 -march=i686 -mtune=generic -Wa,-mtune=generic32 -ffreestanding -DCONF
IG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -pipe -Wno-sign-compare -fno-asynchro
nous-unwind-tables -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -fno-stack-protector -
fno-omit-frame-pointer -fno-optimize-sibling-calls -Wdeclaration-after-statement
 -Wno-pointer-sign -fwrapv   -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(
version)"  -D"KBUILD_MODNAME=KBUILD_STR(version)"  -c -o init/version.o init/ver
sion.c
...

普段は make のシンプルなログで異常がないかどうかだけをチェックします。ビルドエラーに遭遇したら make V=1 で詳細なコンパイルオプションを眺めて原因を考えます。便利ですねえ。

Automake ではできないの?

良いモノは見習いましょう。Automake でログを抑制する方法はないのでしょうか?

残念ながら、ネットでちょこっと調べた限りではやり方がわかりませんでした。誰かご存じないですか?

編集者: すずき(更新: 2009年 11月 3日 17:43)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2009年 11月 12日

重いだけ牧場

以前から mixi アプリのサンシャイン牧場というゲームをやっています。ゲームを一言で言えば「重い」です。とにかく重い。重すぎる。

その他にも下記のような特徴があります。

  • 開発元が中国だからなのか、漢字が変、日本語も変。
  • 何をするのもとにかく時間がかかる。
  • 突如、操作を受け付けなくなる。
  • 虫の数、作物の状態の表示が更新されない。
  • 操作中に「長時間操作していない」と言われ、タイトルに戻される。

どうもまともな部分がないな…。

ついに牧場ご臨終

そんなサンシャイン牧場ですが、今日は新たな一面を見せてくれました。


無人の牧場

畑は真っ白、牧場は無人、名前は「null さん」だとさ。なんとまあ…。

最近、有料アイテム制度を追加しているようですが、こんな状態のまま金取るの?無神経すぎる。

編集者: すずき(更新: 2009年 11月 12日 22:03)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2009年 11月 16日

経過日を年月日に変換

ある時点からの経過日(0 基点)を年月日にする、なんていかにも学校の授業で出てきそうなアルゴリズムですが、世間では需要がないのか、名前が付いているようなアルゴリズムがありません。

練習問題にちょうど良かったので、いっちょ考えてみました。鈴木アルゴリズム完成!なーんて言えれば良かったんですけど、大した物はできませんでした。

その代わりといってはなんですが、考え方を細かくメモっていきたいと思います。今日は月日の変換、後日に年の変換を扱います。

文章をうだうだ読むのが面倒くせえ!って人のために、実装例も載せる予定です。ライセンスを特に明示していなければ、修正 BSD ライセンスを適用します。

グレゴリオ歴の性質

年月日のルールを決めるのは暦です。現在採用されている暦の主流は 1582年頃に採用が始まった「グレゴリオ歴」です。下記の性質があります。

  • 1年は 365日(平年)か 366日(閏年)
  • 1年は 12ヶ月
  • 1月は 28日(平年 2月)29日(閏年 2月)30日(4,6,9,11月)31日(1,3,5,7,8,10,12月)のどれか
  • 1日は 24時間
  • 1時間は 60分
  • 1分は 60秒

閏年は暦と地球の季節がずれないようにする仕組み(※1)です。もっと簡単に言うと、平年より 1日長い年のことです。平年/閏年は下記のルールで決まります。

  1. 西暦が 4で割り切れる年は閏年(1年が 366日)
  2. 西暦が 100で割り切れる年は平年(1年が 365日)
  3. 西暦が 400で割り切れる年は閏年(1年が 366日)

変なルールに見えるかもしれませんが、人類が苦労して「時間とはなんぞや?暦とはなんぞや?」を定義してきた証なのでしょう。

(※1)地球の公転周期(1年)は自転周期(1日)の 365倍と 1/4 日くらいです。単純に暦を 1年 = 365日としてしまうと 4年で 1日分、季節と暦がずれてしまいます。その差を補正するために閏年が作られました。

邪魔な 2月

初めに経過日→月日の変換を考えます。その際に邪魔なのが年によって長さが変わる 2月です。

例として「1/1 から 60日後は何月何日か?」を考えてみます。平年(2月が 28日間)ならば答えは 3/2、閏年(2月が 29日間)ならば答えは 3/1 です。2月の存在によって、経過日と月の対応関係がずれてしまうのです。

年によって計算方法を変えるのは面倒です。以下のように経過日の基準点を変えて一通りの計算方法で、経過日→月日を計算できるようにします。


3/1 を経過日 0日とし、2月を最後に持って行く

つまり3月を一年の始まり(正確には 3/1 を経過日 0日とする)とし、来年の 2月を当年の最終月 14月として考えます。こうすると経過日と各月の対応関係が固定されるため、2月の長さが変化しても計算に影響が出ません(後ほどまた説明します)

経過日から月日への変換

では実際に経過日から月日を計算してみます。使うのは下記のテーブル(※2)です。

各月 1日の経過日月の長さ
3 0 31日
4 31 30日
5 61 31日
6 92 30日
7 12231日
8 15331日
9 18430日
1021431日
1124530日
1227531日
1330631日
1433728 or 29日

テーブルの 2列目は「その月の 1日を表す経過日」を表しています。調べたい経過日と、2列目で大小比較すれば、調べたい経過日が何月なのかがわかります。何月なのかわかれば何日か?も簡単に分かります。

例として 100 を考えましょう。
まず 92(6/1)< 100 < 122(7/1)から 6月であることがわかります。
さらに 100 - 92(6/1)= 8 ですから 6/1 から 8日後、つまり 6/9 だとわかります。

この計算方法の利点は、各月の 1日に対応する経過日だけ考えれば計算できることです。さきほど 2月の長さは気にしなくて良いと言った理由はここにあります。

2月は最終月のため、長さが変化しても各月の 1日に対応する経過日は変化しません。というより各月の 1日に対応する経過日を変化させないようにするために、わざわざ 2月を最後に回したのです。

実装例

実装する関数の仕様は下記の通りです。

date
3/1 からの経過日を渡します。値域は 0〜365 です。
month
変換後の月を返します。値域は 3〜14(翌年 2月)です。
days
変換後の日を返します。値域は 1〜31 です。
返り値
成功ならば 0 を返します。エラーが起きた場合は -1 を返します。

この処理を C 言語で書くと下記のようになります。

経過日から月日への変換、実装例

int date_to_month(int date, int *month, int *days)
{
        static int m_date[] = {
                0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337,
        };
        int m, d;
        int i;

        if (date < 0 || 365 < date) {
                return -1;
        }

        for (i = 0; i < 12; i++) {
                if (date < m_date[i]) {
                        break;
                }
        }
        m = i + 2;
        d = date - m_date[i - 1] + 1;

        if (month) {
                *month = m;
        }
        if (days) {
                *days = d;
        }

        return 0;
}

負の値や、1年(最長 366日)以上の日数に対しては正常に動作しません。エラー処理として 366以上の値や負の値を渡したときにエラーを返すこととします。

きちんと変換できるか、異常値に対してエラーを返すかどうか、-3 から 369 までの経過日を与えてテストします。

経過日から月日への変換、テスト関数

int main()
{
        int m, d;
        int result, i;

        for (i = -3; i < 370; i++) {
                result = date_to_month(i, &m, &d);
                if (result == -1) {
                        printf("date:%3d -> error\n", i);
                        continue;
                }
                printf("date:%3d -> %2d/%2d\n", i, m, d);
        }

        return 0;
}

実行結果は下記の通りです。適当に端折ってあります。

経過日から月日への変換、実行結果
date: -3 -> error
date: -2 -> error
date: -1 -> error
date:  0 ->  3/ 1
date:  1 ->  3/ 2
...(略)...
date:100 ->  6/ 9
date:101 ->  6/10
date:102 ->  6/11
...(略)...
date:364 -> 14/28
date:365 -> 14/29
date:366 -> error
date:367 -> error
date:368 -> error
date:369 -> error

この関数は月のパラメータに 13月やら 14月を返します。しかし後ほど翌年の 1月、2月へ変換してつじつまを合わせますので、ここでは何も変換しません。

ある月の 1日を表す経過日を求めるには、下記の漸化式を用います。
(ある月の 1日を表す経過日) = (前月の 1日を表す経過日) + (前月の長さ)
要はテーブルの 2列目(各月 1日の経過日)と 3列目(月の長さ)を足すと、次の月の 1日を表す経過日が計算できるということです。

また今度

経過日から月日へ変換できたところで、また今度。次は経過日から年への変換を書く予定です。

編集者: すずき(更新: 2009年 11月 23日 02:32)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2009年 11月 18日

経過日を年月日に変換 - その 2

前回(2009年11月16日の日記参照)は経過日から月日への計算を行いました。残るは年の計算です。

グレゴリオ歴の周期性

前回も紹介したとおり、グレゴリオ暦の平年、閏年には下記の法則があります。

  1. 平年は 365日、閏年は 366日
  2. 西暦が 4で割り切れる年は閏年(1年が 366日)
  3. 西暦が 100で割り切れる年は平年(1年が 365日)
  4. 西暦が 400で割り切れる年は閏年(1年が 366日)

4年周期は平年、平年、平年、閏年のパターンです。

100年周期は 4年周期を 25回繰り返すだけですが、最後の 100年目だけは閏年ではありません。

400年周期は 100年周期を 4回繰り返すだけですが、最後の 400年目だけは閏年になります。400年以上を扱うルールはありませんので、以降 400年周期で同じパターンが続きます。

図示すると下記のようになります。オレンジの四角が閏年を表しています。


閏年のパターン

各周期の日数の計算式は下記の通りです。

  1. 1年は 365日
  2. 4で割り切れるときは閏年、つまり最後の年だけ +1日
    365+365+365+366
    =365*4+1
    =1461
  3. 100で割り切れるときは平年 、つまり最後の年だけ -1日
    1461+1461+…++1461+1460
    =1461*25-1
    =36524
  4. 400で割り切れるときは閏年 、つまり最後の年だけ +1日
    36524+36524+36524+36525
    =36524*4+1
    =146097

パターンがわかってしまえば、与えられた経過日にこのパターンがいくつ含まれているか?を計算するのみです。

経過日から年への変換

では実際に経過日から年を計算してみます。しつこいですがパターンは下記 4つです。経過日にこれらのパターンがいくつ含まれているか調べます。

  • パターン A: 400年 = 146097日
  • パターン B: 100年 = 36524日
  • パターン C: 4年 = 1461日
  • パターン D: 1年 = 365日

なぜ上記パターンの数を求めれば年数が出るのか?がわかる人は次の章を飛ばして読んでください。

桁の話

ここでは桁の概念についてと、年への換算にどう使うか?を補足させていただきます。

私たちにおなじみの 10進数は 1234 のように書きますが、これってどういう意味でしょうか?

10進数の 1桁目は 10^0 がいくつ含まれているか、2桁目は 10^1 がいくつ含まれているかを示します。n桁目は 10^(n-1) がいくつ含まれているか?を示します。

ですから 10進数で 1234 は(1 * 10^3 + 2 * 10^2 + 3 * 10^1 + 4 * 10^0 = 1234)という数(10進数表記)を表します。

当たり前?でもこれは m進数でも同様で、n桁目は m^(n-1) がいくつ含まれているか?を示します。

ですから 8進数の 1234 は(1 * 8^3 + 2 * 8^2 + 3 * 8^1 + 4 * 8^0 = 668)という数(10進数表記)を表します。

経過日から年を求める場合も、これと似た考え方ができます。各パターンの数を桁と見なして(400年の桁、100年の桁、4年の桁、1年の桁)、10進数へと換算してやればよいのです。

各パターンの数(400年、100年、4年、1年)が 1, 2, 3, 3 であれば(1 * 400 + 2 * 100 + 3 * 4 + 3 * 1 = 615)という年(10進数表記)を表します。

このように各パターンの数を求めてあげることで、年数が計算可能なのです。

経過日から年への計算式

パターン A の数は(経過日 / 146097)です。余りの経過日は 400年未満のどこか(0年3月1日〜399年2月29日)を表します。これはパターン B の計算に回します。

パターン B の数は(経過日 / 36524)です。余りの経過日は 100年未満のどこか(0年3月1日〜99年2月28日)を表します。余りは同様にパターン C の計算に回します。

しかし 146096日(399年2月29日)の場合に 3となるべきところが 4になり間違えてしまうため、特別に 3とします。その際の余り経過日は 99年2月29日ですから 36525 - 1 = 36524日(開始が 0日のため 1引く)となります。

パターン C の数は(経過日 / 1461)です。余りの経過日は 4年未満のどこか(0年3月1日〜3年2月29日)を表します。余りは同様にパターン D の計算に回します。

パターン D の数は(経過日 / 365)です。余りの経過日は 1年未満のどこか(0年3月1日〜0年2月28日)を表します。ここの余りは経過日から月日を求める計算に回します。

しかし 1460日(3年2月29日)の場合に 3となるべきところが 4になり間違えてしまうため、特別に 3とします。その際の余り経過日は 0年2月29日ですから 366 - 1 = 365日(開始が 0日のため 1引く)となります。

実装例

実装する関数の仕様は下記の通りです。

date
400で割り切れる西暦(1600年、2000年など)の3月1日からの経過日を渡します。値域は正の整数です。
year
年を返します。値域は正の整数です。
mod
1年に満たない経過日を返します。値域は 0〜365 です。
返り値
成功ならば 0 を返します。エラーが起きた場合は -1 を返します。

この処理を C 言語で書くと下記のようになります。

経過日から年への変換、実装例

int date_to_year(int date, int *year, int *mod)
{
        int a400, a100, a4, a;
        int m400, m100, m4, m;

        if (date < 0) {
                return -1;
        }

        a400 = date / 146097;
        m400 = date % 146097;
        if (m400 == 146096) {
                a100 = 3;
                m100 = 36524;
        } else {
                a100 = m400 / 36524;
                m100 = m400 % 36524;
        }
        a4 = m100 / 1461;
        m4 = m100 % 1461;
        if (m4 == 1460) {
                a = 3;
                m = 365;
        } else {
                a = m4 / 365;
                m = m4 % 365;
        }

        if (year) {
                *year = a400 * 400 + a100 * 100 + a4 * 4 + a;
        }
        if (mod) {
                *mod = m;
        }

        return 0;
}

これで経過日から年への変換は完成ですが、まだテストが終わっていません。

月日の変換のときは、入力に対する答えがたかだか 366通りと少なかったため、目でチェックしました。しかし今回は 400年つまり 146097日もの数をチェックしなければなりません。こんな数を目で一々チェックしていたら頭がおかしくなります。

テストの方法についてはまた次回に。

編集者: すずき(更新: 2009年 11月 23日 02:32)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2009年 11月 19日

経過日を年月日に変換 - その 3

前回(2009年11月18日の日記参照)は経過日から年の計算を行いました。今回はそのテストを行います。

テストの方法

そもそもこの問題を解き始めた動機は、年月日から経過日への変換関数はあるけど、逆はないよね?でした。要するに世の中には年月日から経過日を計算する、信頼できる関数があるってことです。

テストの方法は下記の通り、
経過日 --(今回作成の関数)-> 年月日 --(実績ある関数)-> 経過日
として、同じ経過日が出てきたら OK、違っていたら NG です。

年月日から経過日(修正ユリウス日)への変換関数にはフリーゲルの公式を選択しました。

Wikipedia ユリウス通日の項から引用)
グレゴリオ暦 y年 m月 d日午前 0時の修正ユリウス日は、x 以下で最大の整数を floor(x)で表すと、
floor(365.25 * y) + floor(y / 400) - floor(y / 100) + floor(30.59 * (m - 2)) + d - 678912

実装する関数の仕様は下記の通りです。

year
グレゴリオ歴の西暦を渡します。値域は 1 以上です。
month
グレゴリオ歴の月を渡します。値域は 1〜12 です。ただし 1年の場合は 3〜12 です。
days
グレゴリオ歴の日を渡します。値域は 1〜31 です。グレゴリオ暦にない日(閏年でない年の 2月29日など)を渡した場合はエラーになります。
mjd
修正ユリウス日を返します。値域は -678516(1年3月1日)以上 です。
返り値
成功ならば 0 を返します。エラーが起きた場合は -1 を返します。

この処理を C 言語で書くと下記のようになります。float へのキャストがかなりウザいですが、気にしないでください…。

フリーゲルの公式、実装例

int cal_to_mjd(int year, int month, int day, int *mjd)
{
        int chk[] = {
                31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
        };
        int u, d;

        if (month < 1 || 12 < month ||
            day < 1 || 31 < day) {
                return -1;
        }
        if (year % 400 == 0) {
                u = 1;
        } else if (year % 100 == 0) {
                u = 0;
        } else if (year % 4 == 0) {
                u = 1;
        } else {
                u = 0;
        }
        if (chk[month - 1] + u < day) {
                return -1;
        }

        if (month == 1 || month == 2) {
                year -= 1;
                month += 12;
        }
        if (year < 1) {
                return -1;
        }

        d = (int)(
                floor(365.25 * (float)year) +
                floor((float)year / 400.0) +
                - floor((float)year / 100.0) +
                floor(30.59 * ((float)month - 2.0)) +
                (float)day - 678912.0 );

        if (mjd) {
                *mjd = d;
        }

        return 0;
}

テストを行う前に、私の作った関数とフリーゲルの公式が取る「引数の差」について考える必要があります。

引数私の作った関数フリーゲルの公式
経過日 400で割り切れる年(基準年とする)
の3月1日を 0日とする経過日
修正ユリウス日
(1858年11月27日を 0日とする経過日)
基準年からの経過年 西暦(グレゴリオ歴)
月(3月〜14月) 月(1月〜12月、グレゴリオ歴)
日(1日〜31日、グレゴリオ歴) 日(1日〜31日、グレゴリオ歴)

以上から、私の作った関数とフリーゲルの公式の引数では、経過日、年、月の 3つが異なっています。まずはこの差を埋める補助関数を作ります。

引数の変換

経過日については、修正ユリウス日から適当な値(でたらめという意味ではありません)を引いて、3月1日を 0とするような日に直してあげます。

基準とする日は 400年で割り切れる年ならどこでも良いです。しかしグレゴリオ暦の採用年が 1582年以降であることを考えると、そこ付近のグレゴリオ暦にはあまり意味がありません。1600年あたりを開始日とするのが妥当でしょう。

経過日 0日が表す 1600年3月1日の修正ユリウス日は -94493日です(フリーゲルの公式より、計算省略)。修正ユリウス日に 94493 を足せば経過日へ変換できます。

年については、経過日をグレゴリオ暦の 1600年を基準としたので、結果に 1600を足せばグレゴリオ暦の年に変換できます。

月については、3月〜12月まではそのまま、13月、14月を翌年の 1月、2月と考えます。これで経過日、年月日ともにフリーゲルの公式と揃えることができました。

実装する関数の仕様は下記の通りです。

mjd
修正ユリウス日を渡します。値域は -94493(1600年3月1日)以上 です。
year
グレゴリオ歴の西暦を返します。値域は 1600 以上です。
month
グレゴリオ歴の月を返します。値域は 1〜12 です。
days
グレゴリオ歴の日を返します。値域は 1〜31 です。
返り値
成功ならば 0 を返します。エラーが起きた場合は -1 を返します。

この処理を C 言語で書くと下記のようになります。

修正ユリウス日からグレゴリオ歴への変換

int mjd_to_cal(int mjd, int *year, int *month, int *day)
{
        int base, date, y, m, d, mod;
        int result;

        base = 1600;
        date = mjd + 94493; //date 0 is 1600/3/1
        date += (1600 - base) / 400 * 146097; //date 0 is base/3/1

        result = date_to_year(date, &y, &mod);
        if (result == -1) {
                return result;
        }
        result = date_to_month(mod, &m, &d);
        if (result == -1) {
                return result;
        }

        y += base;
        if (m > 12) {
                y += 1;
                m -= 12;
        }

        if (year) {
                *year = y;
        }
        if (month) {
                *month = m;
        }
        if (day) {
                *day = d;
        }

        return 0;
}

上記で説明したこと以外に、mjd_to_cal 関数では基準年を変更できるようになっています。base = 1200 にすれば 1200年3月1日以降の修正ユリウス日を扱えます。ただし負の数、0年には対応していないため、最小値は 400年3月1日(base = 400)です。

テスト

きちんと変換できるか、異常値に対してエラーを返すかどうか、-94495(1600年3月1日の 2日前)から 944929(4446年1月2日)までの経過日を与えてテストします。

経過日から月日への変換、テスト関数
int main()
{
        int y, m, d, mjd;
        int f, result, i;
        int tmin, tmax;

        f = 0;
        tmin = -94495;
        tmax = 944930;
        for (i = tmin; i < tmax; i++) {
                result = mjd_to_cal(i, &y, &m, &d);
                if (result == -1) {
                        printf("mjd->date:%3d -> error\n", i);
                        continue;
                }
                result = cal_to_mjd(y, m, d, &mjd);
                if (result == -1) {
                        printf("date->mjd:%4d/%2d/%2d -> error\n", y, m, d);
                        continue;
                }
                if (i != mjd) {
                        printf("mismatch!!\n");
                        printf("mjd->date:%5d -> %4d/%2d/%2d\n", i, y, m, d);
                        printf("date->mjd:%4d/%2d/%2d -> %5d\n", y, m, d, mjd);
                        f = 1;
                }
        }
        if (f == 0) {
                printf("Test Passed, mjd [%d, %d]\n", tmin, tmax);
        }

        return 0;
}

実行結果は下記の通りです。

経過日から年月日への変換、テスト結果
mjd->date:-94495 -> error
mjd->date:-94494 -> error
Test Passed, mjd [-94495, 944930]

1600年3月1日より前の日付はエラーになり、それ以外はテストにパスしました。どうやら正しく変換できているようです。

残る課題

ネットで調べていたら、経過日から月日へ変換する際にループを回すのは遅くてナンセンスという記述を見つけてしまいました。な、なんだってぇー!?

高々 12回、平均 6回のループがそんなに遅いだろうか…?計算一発で出す方式を考えて、ループ方式と速度比較しようと思います。

編集者: すずき(更新: 2009年 11月 23日 02:44)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2009年 11月 22日

誕生日?焼き肉だろ!

同期の誕生祝いに焼き肉屋に行きました。

同期で誕生祝いをするときはケーキを買って行って、食事の最後に出すのですが、今回は焼き肉とケーキというヘビーすぎる組み合わせになりました。

店のチョイスからしておかしくね?というツッコミはその通りな気がしますが、こまけぇこたぁいいんだよ。みんな食ってたからいいんです。

編集者: すずき(更新: 2010年 7月 30日 23:20)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2009年 11月 29日

子供の頃の夢

社会人になってすっかり忘れていたのですが、子供の頃、ラジコンが欲しかったのです。特に車タイプと空飛ぶタイプが欲しかったのです。

車タイプは大学生の時に買いました。部屋の中でも遊べるくらいの小さいやつを買ったのですが、モーター音があまりにうるさくて近所迷惑だったのですぐ止めました…。

今日、ヘリコプターのラジコンを、しかも「室内用」と書いてあるラジコンを見つけたので思わず買ってしまいました。単三電池がたくさん必要と書いてあったので、充電式エボルタ 8本と一緒にまとめ買いです。

いざ寮の廊下で飛ばしてみると、結構楽しいのですが、やはりモーター音がうるさくて、かなり近所迷惑な音がします。

寮の部屋でもやってみましたが、やはりうるさいのと、狭すぎてすぐに事故って全然楽しくありません。いったんぶつかると吹っ飛んで、ピンボールのようにあちこちにぶつかっります。今にも壊れそうです。

「空を自由に飛びたいな〜。」「えっ?何!?聞こえないよ!!」

飛行機もヘリコプターも、ものすごい音たてて飛んでいます。エンジン近くでは会話が不可能なほどの爆音です。

空を自由に飛ぶと言えば、ドラえもんに登場するタケコプターですが、作中では人間一人を軽々と持ち上げ、それでもかなりの加速力を発揮しています。

飛行機やヘリの騒音から想像するに、タケコプターの騒音も相当なもので、飛行中の会話なんて不可能ではないでしょうか?

でもドラえもんやのび太はタケコプターで飛行中でも、地上に居るときと同じように会話しています。未来の道具はとても静かなのでしょう、羨ましいですね…。

編集者: すずき(更新: 2010年 7月 30日 23:14)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



こんてんつ

open/close wiki
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報