忍者ブログ

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

小数計算の誤差を回避する

ききひじの競プロ備忘録

割り算の結果が小数になる場合、その誤差が時に問題を生じさせる。
特に比較をするときなどは顕著だろう。
その解決策である。

因みに私は記事を書いてなおよくわかっていない。

回避策1:少しだけ小さい数を足す

割られる数が整数などの場合、計算結果に、例えば0.00001のような小さめの値を足すという方法がある。

double ans = 241 / 60 + 0.00001;

「少しだけ」が曖昧なので、妥当な数字がどれくらいかを考えるのは難しい気がする。
また割られる数が小数以下の細かい数字の場合、この方法をとることが出来ない。


回避策2:10のn乗倍してから、整数として計算する。

整数xを整数yで割る。このとき、商を10^-nの精度で求めたいとする。
解決策2では、xを先に10^n倍してyで割るのだ。そして計算結果を10^-n倍すればよい。

もし計算結果をそのまま出力するとか、文字にするのならば10^-n倍しないことも可能だろう。こうすると完全にずれはなくなる…気がする。

// n = 1, y=2 のとき
const int a = 何かしらの値1
const int b = 何かしらの値2

cin>>x;
x = x * 10 / 2;
cout<< x / 10 << '.' << x % 10 << flush;

また、計算が続くのならば、すべての計算が終わった段階で10^-n倍するとよいかもしれない。 この方法で注意すべきは、変数のオーバーフローである。特に計算が長く続き、かつ最後に10^-n倍をする場合、その計算途中で桁が溢れる危険があるので使う際には留意されたし。


回避策3:そもそも計算しない

そもそも小数を扱わなければいけないような計算をしなければいい。

例えば、入力xについて、xを7で割った商で条件分岐する場合を考える。
このとき、境目となる値を先に7倍し、7倍された値とxを比較すればよいのだ。

before
// a > b
const double a = 何かしらの値1
const double b = 何かしらの値2

cin>>x;
double quotient = x/7;
if(quotient > a){
  //何かしらの処理
}
else if(quotient > b){
  //何かしらの処理
}
else{
  //何かしらの処理
}

after AやBは可能なら先に自分で計算をしておくとよりよい(のだろうか)。
// a > b
const double A = 何かしらの値1*7
const double B = 何かしらの値2*7

cin>>x;
if(x > A){
  //何かしらの処理
}
else if(x > B){
  //何かしらの処理
}
else{
  //何かしらの処理
}

拍手[0回]

PR