誤差を許容して比較する ≒ (C# WPF)

C#

数字を計算していると丸めの影響でどうしても誤差が出ます。
誤差を許容できる場合、数値同士を比較する(a==b)にはどうしたらよいでしょうか?

if (Math.Abs(a - b) < delta)
{
}

差(a-b)の絶対値を取って、それが許容できる誤差(delta)以下かどうかを判定するのがスマートです。

私が困ったパターンは、Timerの一定Interval毎に条件に一致するか評価するケースでした。
例えば30秒毎にイベントが発火していて、5分毎に別のイベントを起こしたい場合です。
シンプルに解決するには30秒のTimerと5分のTimerをそれぞれ作ればよいです。

なぜか私は1つのTimerでやりくりしてみたくなりました。
方法としては、経過時間を長い方のイベント間隔で割ります。
割り切れればイベントを起こしたいのですが、ここで問題が起きます。

基本的にTimerは正確ではない = 30秒のIntervalでTickを起こしていても、30.000000秒毎に発火しているわけではなく、数ミリ秒ずれるのです。なので神がかった偶然でぴったり0にならない限り、ほぼ100%割り切れません。
なので小数点部分を取ってきて誤差として100ミリ秒ほど認めてあげます。

double 余り =(経過時間 / 5分)% 1.0
if(余り< 100 msec)
{
  やりたい処理
}

上記で大丈夫かなぁと思ってたらまたしてもダメでした。
誤差って高い方にでることもあれば低い方に出ることもあるんです。

どういうことかというと、5分と1ミリ秒の場合、1ミリ秒余りとなって誤差以内になります。
一方4分59秒と999ミリ秒の場合、 4分59秒と999ミリ秒 がそのまま余りになります。
これは当然ですが、100ミリ秒より大きいですね。

ということで条件式を追加します。

if(余り< 100 msec || (5分-余り)< 100 msec)

Intervalを2つ設定したかっただけなのに意外と面倒ですね。
ここから学んだ教訓ですが、Timer使う場合は2個インスタンス作った方が楽ですね。

コメント