環境:VS2008、MFC
double型で宣言した数値に「4.2」などの数字を入れ、
ブレークを張って中を見てみると「4.199999.....」となってしまいます
そのため、#define 4.2 と定義したものと整合性がとれません
きちんと「4.2」が入るにはどうすれば良いのでしょうか?
「整合性がとれない」とはいかなる意味ですか?
double,floatには誤差がつきものです。
有限の桁数ではどんなにがんばっても1/3を正確には現わせないのと同じこと。
# なので == で等値判定をしてはなりません。
== で等値判定が出来ないという意味でした。
== はいけないのですね
一度、#defineの値をdouble型に入れてから==で判定するなどしないといけないのでしょ
うか?
何かスマートな判定方法はないのでしょうか?
> 一度、#defineの値をdouble型に入れてから==で判定するなどしないといけないのでし
ょうか?
いやだから == 使っちゃダメだってば。
数値にも、strcmpのようなAPIがあるのでしょうか?
探し方が悪いのか、検索で見つかりませんでした
もしくは、小数点を含む数値の比較ってMFCではできないのでしょうか?
επιστημηさんが書いてらっしゃいますが
普通の計算機での実数の扱いは浮動小数点数という
固定長(つまり有限の桁数)の表現方式で取り扱います。
その上、2進数(10進ではない)なので10進で
有限の桁数で表現できるものでも二進では極僅かに誤差が
出てしまうことがありますし、有限の桁数では表現できない
こともあります。
#define 4.2 とソース上に書いてあるからといっても
コンパイルした時に十進で 4.2 が、2進数での浮動小数点数
がたまたま誤差を含まないとしても、比較相手がぴったり
4.2 という保証がどこかにありますか?
比較相手が例えば 4.2000013 という場合単純に等号で比較しても
不一致と判定してしまいす。誤差の範囲に収まっていれば
等しいと判定するのが浮動小数点数の場合通常なのです。
単純に考えるのであれば、範囲で比較するしかないのではないでしょうか。
#include <iostream>
#include <float.h>
if ( (srcValue - DBL_EPSILON) < destValue &&
destValue < (srcValue + DBL_EPSILON ) )
{
std::cout << OK << endl;
}
私の場合は判定が必要なデータは整数化しています
(値を計算する場合は、計算途中はdoubleで行い
最終結果を整数化)。
有効桁数分を10のN乗をかける
↓
0.1の桁を四捨五入
↓
整数型でキャスト
※とうぜん比較値も整数化しています。
静観してましたが、やや気になるので発言します。一般に
#define AAA 4.2
void Foo()
{
double bbb = ( double)4.2;
if( bbb == AAA){
// 一致した(必ず一致します)。
}
}
は、「完全に正しい」コードで、「一致した」に必ず入ります。
当然ですが、エラーも警告もでません。
これは、比較演算子==が実行されるとき、AAAを自動的にdouble値に
変換するからです。
これを踏まえた上で、めあさんが、どのようなコードで「一致しない」
状況になっているのかを、再度確認してみたいのですが、いかがでしょう。
私も仲澤さんに賛成です。
以下のコードを実行すると
double d0 = 1.0 / 3.0;
double d1 = 1.0 / 3.0;
double d2 = 1.0 / 3;
double d3 = 10.0 / 3.0 / 10.0;
TRACE(d0 %s d1\n, (d0 == d1) ? == : !=);
TRACE(d0 %s d2\n, (d0 == d2) ? == : !=);
TRACE(d0 %s d3\n, (d0 == d3) ? == : !=);
結果はこうです。
d0 == d1
d0 == d2
d0 != d3
結果として同じ値が期待される演算ではなく、
全く同じ演算を行えば全く同じ結果が得られるのは
当然といえましょう。
要するにめあさんに聞きたいのは、
・結果として同じ値が期待される演算結果の比較なのか?
・全く同じ演算結果の比較なのか?
どちらなの?ということです。
前者なら他の人のおっしゃる通りですし、
後者なら一致してしかるべきですので、何か別の問題が
あるはずです。
>もしくは、小数点を含む数値の比較ってMFCではできないのでしょうか?
strcmpのような関数はないです。
マイクロソフトがすすめる方法は、
みいさんの
2011/11/28(月) 09:49:36
の方法です。
僕も、どうしても比較なければいけない場合は、同じ方法を使います。
もし、ある程度許されるのであれば、範囲で判定します。
みなさんご回答ありがとうございます
仲澤さんやbunさんがおっしゃるとおり、
== で「一致した」ということになっていました。
値を中を見て、不動小数点が入っているので
一致しないものと勘違いしておりました。すみません。
ちなみに、自分がやろうとしていた事は、
・アプリからバージョンを取得
・バージョンがX.XX以下なら除外
というものを想定していました
なので、正確には==ではなく<=ですね
しかし、浮動小数点が絡む計算については勉強になりました
今後、使う事があれば参考にさせてもらいます。ありがとうございました。
ですか。とりあえずはうまく動くのかもしれませんが、
本来「バージョン番号」と「浮動少数(又は実数)」とは関係の無い「型」です。
「バージョン番号」型の「<=」演算をdouble型の「<=」演算で代用するのは
間違いであると言わざるをえません(vv;)。
(将来想定される問題)
バージョンが MM.ss.bb 形式に変更になった( ver 4.1.1 等)。
数値の後ろにアルファベットが入ることになった( ver 4.1b 等)
・・・とか。
あ、なるほど
無理にdouble型に直さないまでも、「.」で区切って
個々の数字として判定すれば良かったのですね
思いつきませんでした。
Ver4.1.1等のバージョンも存在するかもしれないとのことなので、
この方式でやってみようと思います。ありがとうございます。