2007/07/22
時刻処理なのに浮動小数点絡みのバグ
AirOneのOutlook同期の時、時刻のずれる予定がある、というバグ報告がありました。
実際に試してみると、9時9分の予定は問題無いのですが、9時10分の予定をOutlookからAirOneにインポートすると9時9分の予定になります。
コードを調べてみると、Outlookから渡る時刻情報が怪しげなDATE型です。DATE型の説明は次のようになっています。
(マイクロソフトファンには常識なのかもしれませんが)なんと、Outlookから時刻情報が小数で渡ってきます...知りませんでした。
こうなると、9時9分と9時10分の違いは bc(1) でも確認可能です(86400は24*60*60)。
$ bc -l (9*60*60 + 9*60) <==9時9分 32940 (9*60*60 + 9*60)/86400 .38125000000000000000 ((9*60*60 + 9*60)/86400) * 86400 32940.00000000000000000000 (9*60*60 + 10*60) <==9時10分 33000 (9*60*60 + 10*60)/86400 .38194444444444444444 ((9*60*60 + 10*60)/86400) * 86400 32999.99999999999999961600
http://www.codeguru.com/cpp_mfc/ATLDateTime.shtml を参考にしてDATE型からの変換処理を書き直しました。変数名が手抜きですが、元のロジックと新しいロジックの検証コードを示します。
#include <stdio.h>
#include <math.h>
#define DAY_BY_SEC (24*60*60)
#define HALF_SECOND (1.0/172800.0) // Half a second, expressed in days
int main()
{
int err2 = 0;
int err3 = 0;
int h,m,s;
for (h = 0; h < 24; h++) {
for (m = 0; m < 60; m++) {
for (s = 0; s < 60; s++) {
double msdate = ((long)h*60*60 + m*60 + s) / (double)DAY_BY_SEC; /* emuldate DATE type */
/* wrong conversion to h2,m2,s2 */
long sec2 = msdate * DAY_BY_SEC;
int h2 = sec2 / (60 * 60);
int m2 = (sec2 / 60) % 60;
int s2 = sec2 % 60;
/* right conversion to h3,m3,s3 */
/* @see http://www.codeguru.com/cpp_mfc/ATLDateTime.shtml */
double dblDate = msdate + HALF_SECOND;
long nSecsInDay = (long)((dblDate - floor(dblDate)) * 86400);
long nMinutesInDay = nSecsInDay / 60L;
int h3 = (int)nMinutesInDay / 60;
int m3 = (int)nMinutesInDay % 60;
int s3 = (int)nSecsInDay % 60;
printf("%d:%d:%d=> %d:%d:%d or %d:%d:%d\n",
h,m,s,
h2,m2,s2,
h3,m3,s3);
if (h != h2 || m != m2 || s != s2) err2++;
if (h != h3 || m != m3 || s != s3) err3++;
}
}
}
printf("error %d,%d\n", err2, err3);
return 0;
}
この変換処理の正しさを代数的に示そうと http://docs.sun.com/source/806-4847/ncg_goldberg.html を読もうとしたのですが、難しくて挫折しました(難しいので、アリエルの採用試験問題にします)。
もう少し易しい記事でお勧めなのが http://pc.nikkeibp.co.jp/pc21/special/gosa/eg4.shtml です。
そんなに難しくないとは言え、日経の雑誌かつExcelユーザ向け記事で、このレベルに驚きました(Excelユーザを見下し過ぎていた気がします。反省します)。
- Category(s)
- カテゴリなし
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/inoue/floating-point-problem/tbping