ページ 1 / 1
double型の計算ずれについて
Posted: 2016年2月25日(木) 19:08
by double型のずれ
c++,プログラミングを始めたばかりのものです。
プログラム中によくわからないことが起こったので質問させていただきます。
今回ゲームのエフェクトを作っていて if 文による制御をしていた時予期しない動きをしたので。
バグ探しの時,簡略化したコードをあげさせていただきます
コード:
#include "DxLib.h"
double a=0;
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
ChangeWindowMode(TRUE), DxLib_Init(); //ウィンドウモード変更
for(int i=0;i<100;i++){
a+=0.2;//0.2を100回たす
}
if(a==0.2*100){
printfDx("成功");
}else{
printfDx("失敗");
}
WaitKey();//結果があるまで待つ
DxLib_End();// DXライブラリ終了処理
return 0;
}
環境は
win7 64bit
VC++ 2010 Express
DxLIb
となっております。
ここで成功が出るようにしたいのですが
どうすればいいのでしょうか。
しょしんしゃですが、アドバイスよろしくお願いします。
Re: double型の計算ずれについて
Posted: 2016年2月25日(木) 19:16
by つくばさん
すみません Nameを間違えてしまいましたこちらの名前でお願いします
Re: double型の計算ずれについて
Posted: 2016年2月25日(木) 19:19
by 超初級者
計算で求めた値と20との差がきわめて
小さければ成功とみなす、では
いかがでしょうか。
Re: double型の計算ずれについて
Posted: 2016年2月25日(木) 19:41
by みけCAT
無駄に実数演算をしないようにしましょう。
コード:
#include "DxLib.h"
double a=0;
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
ChangeWindowMode(TRUE), DxLib_Init(); //ウィンドウモード変更
int i; // ループの後でも参照できるように外に出す
for(i=0;i<100;i++){
a = (i+1)*0.2; // 誤差がどんどん積もるような足し算の計算を避ける
}
if(i==100){ // 無用な実数の比較を避ける
printfDx("成功");
}else{
printfDx("失敗");
}
WaitKey();//結果があるまで待つ
DxLib_End();// DXライブラリ終了処理
return 0;
}
Re: double型の計算ずれについて
Posted: 2016年2月25日(木) 19:44
by みけCAT
double型のずれ さんが書きました:ここで成功が出るようにしたいのですが
どうすればいいのでしょうか。
「成功が出る」とは、元のコードではどのようなことを表しますか?
これだけの情報だと、「成功を出したいのだから、余計な計算をせずに成功を出せばいい」となってしまいます。
コード:
#include "DxLib.h"
// 無駄なグローバル変数を削除
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
ChangeWindowMode(TRUE), DxLib_Init(); //ウィンドウモード変更
// 無駄なループを削除
// 無駄な分岐を削除
printfDx("成功"); // 成功が出る
WaitKey();//結果があるまで待つ
DxLib_End();// DXライブラリ終了処理
return 0;
}
Re: double型の計算ずれについて
Posted: 2016年2月25日(木) 19:55
by つくばさん
超初心者さん、みけCATさん返信ありがとうございます。
書き方があいまいですみませんでした。
今回求めているのは
変数 aに0.2を100回足したらぴったり0.2*100になるようにしたいものでした.
double型というのはこんなにずれるものなんですか?
できれば double型に足し算するだけで==比較でできるようにしたいのですが
無理なのでしょうか
Re: double型の計算ずれについて
Posted: 2016年2月25日(木) 20:02
by つくばさん
超初級者 さんすみません名前を間違えてしまいました
Re: double型の計算ずれについて
Posted: 2016年2月25日(木) 20:25
by みけCAT
つくばさん さんが書きました:今回求めているのは
変数 aに0.2を100回足したらぴったり0.2*100になるようにしたいものでした.
aを標準の実数型ではなく、適当に実装した数クラスにするといいでしょう。
つくばさん さんが書きました:double型というのはこんなにずれるものなんですか?
DXライブラリを使っていると、float型の精度で計算されているかもしれません。
オフトピック
定量的な評価のコードが出ていないのに「こんなにずれる」とは…?
つくばさん さんが書きました:できれば double型に足し算するだけで==比較でできるようにしたいのですが
無理なのでしょうか
この程度の数なら、整数で計算すればいいでしょう。
コード:
#include "DxLib.h"
double a=0;
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
ChangeWindowMode(TRUE), DxLib_Init(); //ウィンドウモード変更
double adata = 0;
for(int i=0;i<100;i++){
a=(adata+=2)/10.0;//0.2を100回たす
}
if(adata==200.0){
printfDx("成功");
}else{
printfDx("失敗");
}
WaitKey();//結果があるまで待つ
DxLib_End();// DXライブラリ終了処理
return 0;
}
Re: double型の計算ずれについて
Posted: 2016年2月25日(木) 21:30
by Ketty
DXライブラリでは、doubleの精度を保証するためには、
SetUseFPUPreserveFlag(TRUE)を実行する必要があると、↓に書かれています(^v^)
http://hpcgi2.nifty.com/natupaji/bbs/pa ... st&no=1385
Re: double型の計算ずれについて
Posted: 2016年2月26日(金) 09:57
by つくばさん
返信遅れてすみません
みけCATさん Kettyさん 返信ありがとうございます
残念ながらSetUseFPUPreserveFlag(TRUE)では解決しなかったため、
今回はdouble 型ではなく int 型を使うことで解決させていただきました。
皆さんありがとうございました。
Re: double型の計算ずれについて
Posted: 2016年2月27日(土) 20:34
by たいちう
解決になっているので、質問者さんに読まれないかもしれませんが、
元々の疑問が解決していないのではないかと思うので一応書きます。
0.2というのは簡単な小数で、
0.2 + 0.2 + ... + 0.2 == (0.2 * 100) == 20 なのも自明です。
しかし、これは私たちが馴染んでいる10進数での話です。
コンピューターでは2進数が使われていますが、
0.2を2進数で表すと、0.00110011001100110011... という循環小数になります。
double型はfloat型の倍の精度を持っていますが、
無限に続く小数を扱えるわけではないので、どこかで切り捨てることになります。
0.2に非常に近い数値を100回足しても、ぴったり20になる保証はありません。
この事情を10進数で例えると、1/3 + 1/3 + 1/3 が判りやすいと思います。
1/3 == 0.333333333... と無限に続くので、どこかで打ち切ります。
イメージは以下のようなものです。(あくまでもイメージなので、実際とは違います)
コード:
float a = 1.0 / 3; // 0.333333
double b = 1.0 / 3; // 0.333333333333
double c = b + b + b; // 0.999999999999
if (c == 1) {
printf("成功"); // ここには来ない
}
結論としては、超初級者さんの書いたように、誤差を考慮するか、
みけCATさんの書いたように、整数で管理するか、ですね。