2008-03-18

誤差

聞いてくださいよ、今日私はひどいミスをしでかしてしまっていたことに気がついたんですよ。

          float pixelToCell(float pixel_x) { return (pixel_x - cell_origin_x) / cell_width;}
        

こういうpixel_xからcell_xへ変換する関数があったんですね。一種のグリッド(表)を想像してください。グリッドの左端のピクセル座標がcell_origin_x、セルのピクセル幅がcell_width。だから、任意のピクセル座標pixel_xをグリッド内のセル座標に変換するには、pixel_xからグリッド左端の座標を引いて、セルの幅で割ればいい。まあ、良くある形です。

それで、やってしまったミスは次のようなもの。

          float pixel_lower_x = (下限値、含む);
          float pixel_upper_x = (上限値、含まない);
          float cell_lower_ix = floor(pixelToCell(pixel_lower_x));
          float cell_upper_ix = ceil(pixelToCell(pixel_upper_x));
        

半開区間、[pixel_lower_x, pixel_upper_x)を整数のセル座標の範囲[cell_lower_ix, cell_upper_ix)にマップする処理。元の範囲と少しでもかぶっているセルは、範囲に含めなければなりません。

皆さんおわかりですか? おわかりですよね。当たり前だろって? うわーん!

pixel_x - cell_origin_xで情報落ちが起こりえるので、その後floorやceilしたって手遅れなんですね。