2007-08-02

簡単な計算をするときに分かっていなければならないこと

(n=0)かつ(sx + n * m00 - half < left)かつ(m00 > 0)という状況があったとして(すべて整数)、nが一つずつ増えていったときに、いくつになったときに初めて(sx + n * m00 - half >= left)になるかを考える。

sx + n * m00 - half >= left

両辺から同じ値を引いても不等号は変わらないので、

n * m00 >= left - (sx - half)

両辺を正の整数m00で割っても不等号は変わらないので、

n >= (left - (sx - half)) / m00 + (切り下げ誤差)

ただし、/は正の数同士の切り下げ除算である。/の左右は前提条件より正の数である。切り下げ誤差は1未満の小数で0から(m00-1)÷m00の範囲内である。

nが整数の中でいくつ以上なら不等式が成り立つかという話だったので、右辺を切り上げればよく、

n >= (left - (sx - half) + m00-1) / m00

となる。

今度は(n=0)かつ(sx + n * m00 - half > right)かつ(m00 < 0)という状況があったとして(すべて整数)、nが一つずつ減っていったときに、いくつになったときに初めて(sx + n * m00 - half <= right - one)になるかを考える。

sx + n * m00 - half <= right - one

両辺から同じ値を引いても不等号は変わらないので、

n * m00 <= right - one - (sx - half)

m00は負なので、そのままでは割れない。負数が入る除算は処理系定義なので注意。

両辺に-1をかけると左右の大小関係が逆になる。ただし、同じ値だった場合は符号を反転させても同じまま。

n * -m00 >= -(right - one - (sx - half))

両辺を正の整数-m00で割っても不等号は変わらないので、

n >= -(right - one - (sx - half)) / -m00 + (切り下げ誤差)

後は先ほどと同様に切り上げに直して、

n >= (-(right - one - (sx - half)) + -m00-1) / -m00

となる。

これでもいろいろと省略している。勝手に項を移動していたり、加減算や乗算の説明をしていないし、値の範囲を気にしていなかったり、切り上げとか切り下げとか説明していないし。

整数(固定小数点数)の場合はまだ予測しやすい。浮動小数点数なんて扱った日にはいろんなところで誤差が出るので、もうわけわかんね。