double dA;
long lB = 233333;
dA = (double)lB / (double)100);
dAの結果が
dA = 2333.3299999999999
となるのです。
どうしてでしょうか?
メモリを壊しているか、何か理由があるのでしょうか?
2333.33は二進数で表せないので誤差が出ます。
その誤差を回避する方法はあるのでしょうか?
いろいろ試しましたが、わかりません。
教えてください!!
回避する必要あるんですか?
BCD演算を行えば十進ベースでの誤差はありませんが、
そうなると十進数であらわせない数はやっぱり誤差がでます。
無限の精度を持たない限り、誤差は避けられません。
_controlfp 又は、_controll87 で計算精度の変更が出来ます。
unsigned int def = _controlfp(0, 0); // 現在の設定値確保
_controlfp(_RC_NEAR, MCW_RC ); // 丸め指定
_controlfp(_PC_64, MCW_PC ); // 制度指定
dA = lB / 100.0;
_cntrolfp(def, MCW_PC | MCW_RC); // 念のため元に戻す
としてみてください。
この手の誤差はコンピュータでの演算ではある事を前提にロジックを考えるべきだし、
その誤差が本当に最終的な結果に無視できない影響を与えるのかと言う部分も考慮に
入れるべきだと思います。
コンピュータと言うと正確な計算をすると言うイメージを持つ人もいると思いますが、
実数を対象にした場合はどうしても誤差が出てしまうのは避けられないと思います。
あと考えるとしたら最終的な結果の誤差をなるべく減らす為に100倍もしくは1000倍した
整数値で計算しておいて最終的に実数値に戻すと言う手もあると思います。
とは言え、有限表現内での限界はありますから万能だとは考えない事が必要ですね。
double型で計算する以上は提示の例のような誤差が出ても仕方がないと思います。
環境が書かれていませんが、ここはVC++の掲示板なので
DECIMAL型で計算する例を書いておきます。
(エラーチェックは省略しています)
#include <windows.h>
int main()
{
DECIMAL dec1;
DECIMAL dec2;
DECIMAL result;
VarDecFromStr(L233333, LOCALE_USER_DEFAULT, 0, &dec1);
VarDecFromStr(L100, LOCALE_USER_DEFAULT, 0, &dec2);
VarDecDiv(&dec1, &dec2, &result);
BSTR bstr = NULL;
VarBstrFromDec(&result, LOCALE_USER_DEFAULT, 0, &bstr);
MessageBoxW(NULL, bstr, NULL, 0);
SysFreeString(bstr);
return 0;
}
文字列は一部コントロールパネルでの設定値に影響を受けるかもしれません。
MFCが利用可能で精度が低くてもかまわないなら、
COleCurrencyで計算してもよいと思います。