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