visual c++ 2008です
double x = 0;
x += 0.1;
cout << x << '\n';
if(x == 0.1){
//処理
}
このようにプログラムしたところ、if文の条件式がtrueになりませんでした。直前のcoutにより画面には0.1が表示されます。
x += 0.1; ではなく x = 0.1; にすれば大丈夫でしたが、納得できないのでお願いします。
0.1を代入したのに == 0.1 がtrueにならない
Re: 0.1を代入したのに == 0.1 がtrueにならない
0.1を代入したのに == 0.1 がtrueにならないのは、floatやdoubleの仕様ですから諦めるほかありません。
x = 0.1;のときに x == 0.1が真になるのは、おそらくコンパイラの最適化のおかげです。本来は真になりません。
参考http://www.cc.kyoto-su.ac.jp/~yamada/pr ... float.html
x = 0.1;のときに x == 0.1が真になるのは、おそらくコンパイラの最適化のおかげです。本来は真になりません。
参考http://www.cc.kyoto-su.ac.jp/~yamada/pr ... float.html
Re: 0.1を代入したのに == 0.1 がtrueにならない
ごめんなさい。
いろいろな人と相談した結果、僕が勘違いしていた部分がありましたので訂正します。
規格をあたったわけではないのですが、 と書いた場合、x == 0.1が真になるかどうかは不明です。処理系依存で、しかもコンパイルオプションによっても違うかもしれません。
一般論として、浮動小数点数を扱う場合に == と != は使いません。これは前回示したリンク先のお話を読めば理由が分かると思います。
そのかわり、不等号 <, <=, >, >= を使って比較します。 のように。
いろいろな人と相談した結果、僕が勘違いしていた部分がありましたので訂正します。
規格をあたったわけではないのですが、 と書いた場合、x == 0.1が真になるかどうかは不明です。処理系依存で、しかもコンパイルオプションによっても違うかもしれません。
一般論として、浮動小数点数を扱う場合に == と != は使いません。これは前回示したリンク先のお話を読めば理由が分かると思います。
そのかわり、不等号 <, <=, >, >= を使って比較します。 のように。
-
ふりかけ
Re: 0.1を代入したのに == 0.1 がtrueにならない
そのサイトは投稿する直前に見ていました、偶然です。
2進数と10進数の小数に誤差ができるのも知っていましたが、それでも妙です。
浮動小数点型に == を使わない常識は知りませんでした。相談できる人がいるのはうらやましいですね。
beatleさんありがとうございました。
一応解決にしますが、厳密なことが分かる方がいたら教えてくれるとすっきりします。
2進数と10進数の小数に誤差ができるのも知っていましたが、それでも妙です。
浮動小数点型に == を使わない常識は知りませんでした。相談できる人がいるのはうらやましいですね。
beatleさんありがとうございました。
一応解決にしますが、厳密なことが分かる方がいたら教えてくれるとすっきりします。
Re: 0.1を代入したのに == 0.1 がtrueにならない
これはちょっと言い過ぎでは?beatle さんが書きました:一般論として、浮動小数点数を扱う場合に == と != は使いません。
どんな目的でどんな処理なのかによります。
分かりやすい具体例としては、除算を行う前に除数がゼロかどうかを判定するには==や!=を使うべきです。
Re: 0.1を代入したのに == 0.1 がtrueにならない
Visual C++ 2010 Expressでは再現しないですね。
main関数に質問のコードだけを書いたプログラムでも真になりませんか?
一部のバージョンのDirect3Dではデバイスを初期化すると浮動小数点数演算がfloat精度に固定されるなんてことがあるので、そういったものの影響があったりしないですかね。
例えばDXライブラリ使ってると再現するとか。
(追記)
DXライブラリを使ったプログラムの中に組み込んでみたら再現しました。
main関数に質問のコードだけを書いたプログラムでも真になりませんか?
一部のバージョンのDirect3Dではデバイスを初期化すると浮動小数点数演算がfloat精度に固定されるなんてことがあるので、そういったものの影響があったりしないですかね。
例えばDXライブラリ使ってると再現するとか。
(追記)
DXライブラリを使ったプログラムの中に組み込んでみたら再現しました。
Re: 0.1を代入したのに == 0.1 がtrueにならない
確かに言い過ぎだったかもしれません。その上で少し意見を書きます。たかぎ さんが書きました:これはちょっと言い過ぎでは?beatle さんが書きました:一般論として、浮動小数点数を扱う場合に == と != は使いません。
どんな目的でどんな処理なのかによります。
分かりやすい具体例としては、除算を行う前に除数がゼロかどうかを判定するには==や!=を使うべきです。
浮動小数点数同士の除算の場合、ゼロ除算はエラーになりません。少なくともIEEE 754の浮動小数点なら。
IEEE 754の浮動小数点でゼロ除算をすると「無限大」になります。
しかも、ゼロでない数値で割った時も「無限大」になることはあります。例えばこういう場合。
int main(void)
{
float a = 3e38f;
printf("a = %f\n", a);
float b = a / 1e-1f;
float c = a / 0.0f;
printf("b = %f\n", b);
printf("c = %f\n", c);
return 0;
}
従って、浮動小数点数の除算において除数が「0.0」かどうかチェックするのはあまり意味がないと思います。
ですから、僕としては「分かりやすい具体例として」、「除算を行う前に除数がゼロかどうかを判定する」という例は不適当だと思います。
除算する前にゼロかどうかチェックしないといけない、チェックすることに意味がある、と誤解を与えてしまいそうです。
興味でお聞きしたいのですが、他に、==や!=を使うべきである例はありますか?
便乗質問になっていますがお許し下さい。
Re: 0.1を代入したのに == 0.1 がtrueにならない
IEEE754以外の場合もあるというのはおいておいて...beatle さんが書きました:従って、浮動小数点数の除算において除数が「0.0」かどうかチェックするのはあまり意味がないと思います。
ですから、僕としては「分かりやすい具体例として」、「除算を行う前に除数がゼロかどうかを判定する」という例は不適当だと思います。
無限大という結果を得てそれで済む場合ならそれでもよいでしょうが、そうでない場合もあります。
例えば、点(x0, y0)と点(x1, y1)を結ぶ直線の方程式を求める場合を考えてみてください。
このとき、x0 != x1であれば直線の傾きは(y1 - y0) / (x1 - x0)になりますが、x0 == x1 または (x1 - x0) == 0 の場合の方程式は x = x0 ですので、通常、処理を変えないといけなくなります。
特殊な状況ではいろいろあるのですが、状況説明が大変です。beatle さんが書きました:興味でお聞きしたいのですが、他に、==や!=を使うべきである例はありますか?
便乗質問になっていますがお許し下さい。
誰でもわかる例としては、二次方程式が重解を持つかどうかを調べるには、判別式がゼロかどうかで判断するしかありません。
誤差を考慮して、判定式がゼロの近傍であれば重解とする方針もあり得ますが、常にそうすべきとは限りません。
あとは、HUGE_VALと比較する場合には==や!=を使うことは普通にありますね。
Re: 0.1を代入したのに == 0.1 がtrueにならない
書いた後に気付きましたが...たかぎ さんが書きました:誰でもわかる例としては、二次方程式が重解を持つかどうかを調べるには、判別式がゼロかどうかで判断するしかありません。
二次方程式 ax2+bx+c=0 のa, b, cを与えて解を求める場合、解の公式をそのまま使ってしまうと、a=0のときに|x|=∞という結果になってしまいますね。
これは判別式以前の問題です。
数学的には、ゼロで割った結果はそもそも無限大ではないので、何でもかんでもそれで代用するのは無理があるのです。
Re: 0.1を代入したのに == 0.1 がtrueにならない
たかぎさん、分かりやすい説明ありがとうございます。
確かに==や!=で比較するのが必要な場合があることが分かりました。
確かに==や!=で比較するのが必要な場合があることが分かりました。
Re: 0.1を代入したのに == 0.1 がtrueにならない
といいますか、aが「正確に」0の場合はそもそも二次方程式にならないので、たかぎ さんが書きました: 二次方程式 ax2+bx+c=0 のa, b, cを与えて解を求める場合、解の公式をそのまま使ってしまうと、a=0のときに|x|=∞という結果になってしまいますね。
aが「正確に」0かどうかを判定した後で解の公式を適用するのが筋かと。
たかが二次方程式、されど二次方程式。曰く侮り難し。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。
プログラムは思ったとおりには動かない。書いたとおりに動く。