doubleの計算結果が異なる

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
だんごさん
記事: 273
登録日時: 12年前

doubleの計算結果が異なる

#1

投稿記事 by だんごさん » 10年前

リンク
知恵袋だと何度も返信できないのでこちらでも質問させていただきます。

リンク先は説明不足なのでこちらで書きます。
こちらの電卓のコード↓を自分のソフトに移植しました。

コード:

#include <stdio.h>   // printf, puts, fgets
#include <stdlib.h>  // strtod
#include <ctype.h>   // isspace, isdigit
#include <math.h>    // pow
 
unsigned char c;  const char *p, o[] = "+-*/^ ";  double m[26];
 
int get(void) { while (isspace(c = *p++)) ; return c; }
 
double expr(const char *b)
{
    double v;
    if (*b)  // binary operators; power is right associative
        for (v = expr(b + 2); c == b[0] || c == b[1]; )
            c == '+' ? v += expr(b + 2) :
            c == '-' ? v -= expr(b + 2) :
            c == '*' ? v *= expr(b + 2) :
            c == '/' ? v /= expr(b + 2) : (v = pow(v, expr(b)));
    else  // number, parentheses, unary operators, and variable
        get() == '.' || isdigit(c) ? v = strtod(p-1, (char **)&p), get() :
            c == '(' ? v = expr(o), c == ')' ? get() : (c = 1) :
            c == '+' ? v = expr(b) : 
            c == '-' ? v = -expr(b) :
            islower(c) ? v = m[c - 'a'], get() : (v = c = 1);
    return v;
}
 
int main(void)
{
    char s[800];  double v;  int i;
    while (fgets(s, sizeof s, stdin))
        p = s, get() == '?' ?
            v = expr(o), c ? puts("  --err--") : printf("  %.15g\n", v) :
        islower(c) && (i = c - 'a', get() == '=') && (v = expr(o), !c) ?
            m[i] = v : puts("  --err--");
    return 0;
}
これを私のソフトで実行してみたところ、2.2+2.2の結果が4.4000000953674316となりました。
しかし普通に実行してみると4.4ときちんと結果が出ます。
移植後の修正は出力の仕方と、mainのwhile文を無くしたことくらいで、あとは手を付けていません。

知恵袋で書いていますが、double型を2つ足すだけのコードでも同様な結果です。
ただ2.2+5とか、小数点が一回しか出ないのはちゃんと出ます。

足した時に何が原因で数値が変わるのでしょうか?

VC++2010
Windows7
 Dango San

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: doubleの計算結果が異なる

#2

投稿記事 by h2so5 » 10年前

だんごさん さんが書きました: これを私のソフトで実行してみたところ、2.2+2.2の結果が4.4000000953674316となりました。
しかし普通に実行してみると4.4ときちんと結果が出ます。
「私のソフトで実行」と「普通に実行」の違いが分かりません。

だんごさん
記事: 273
登録日時: 12年前

Re: doubleの計算結果が異なる

#3

投稿記事 by だんごさん » 10年前

h2so5 さんが書きました:「私のソフトで実行」と「普通に実行」の違いが分かりません。
「私のソフトに移植して実行」と、「移植せずにコピペだけで実行」です。
申し訳ないです。
 Dango San

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: doubleの計算結果が異なる

#4

投稿記事 by h2so5 » 10年前

double型を2つ足すだけのコードでいいので、再現できる最小限の移植後のコードを書いてください。

だんごさん
記事: 273
登録日時: 12年前

Re: doubleの計算結果が異なる

#5

投稿記事 by だんごさん » 10年前

移植前も移植後も、以下のコードを書いてデバッグして確認しただけです。

コード:

double d1 = 2.2,d2 = 2.2;
double sum= d1 + d2;
あえて動くようにするなら、

コード:

#include <stdio.h>
int main( void ){
	double d1 = 2.2,d2 = 2.2;
	double sum= d1 + d2;

	printf("%.15g",sum);
	return 0;
}
質問に書いた以外に2つの違いとして言えば…DOS(移植前)とDxLib(移植後)くらいでしょうか…。
 Dango San

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: doubleの計算結果が異なる

#6

投稿記事 by ISLe » 10年前

だんごさん さんが書きました:質問に書いた以外に2つの違いとして言えば…DOS(移植前)とDxLib(移植後)くらいでしょうか…。
DXライブラリがDirect3Dのデバイスを作成する際に、浮動小数点数演算が単精度モードになっているのではないでしょうかね。
その場合、double型の値でもfloatの精度で計算されますし、代入で誤差が発生する可能性もあります。

だんごさん
記事: 273
登録日時: 12年前

Re: doubleの計算結果が異なる

#7

投稿記事 by だんごさん » 10年前

ISLe さんが書きました:その場合、double型の値でもfloatの精度で計算されますし、代入で誤差が発生する可能性もあります。
なるほど…。
どうやら大きい数で計算を行った時の結果もおかしな値が返ってきます。
移植前ので計算したら正しいのでこれも精度が原因だと思います…
double型ではないと困りますね…。
 Dango San

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: doubleの計算結果が異なる

#8

投稿記事 by ISLe » 10年前

DXライブラリを使わないで、Direct3Dを直接使えばデバイスを作成する際に精度を維持する設定が可能です。

DXライブラリを使う場合は、SetUse3DFlagでFALSEを指定して3Dデバイスを初期化させなければ良いかもしれません。
その代わりDXライブラリの描画性能は著しく低下するはずです。

DXライブラリ(というかDirect3D9)を使う必要があるのでしょうか。

だんごさん
記事: 273
登録日時: 12年前

Re: doubleの計算結果が異なる

#9

投稿記事 by だんごさん » 10年前

ISLe さんが書きました:DXライブラリ(というかDirect3D9)を使う必要があるのでしょうか。
確かに使用しなくても実装できそうですが、今の私の知識ではできるかどうか…

別の方法を探してみます。ご返信ありがとうございました。
 Dango San

だんごさん
記事: 273
登録日時: 12年前

Re: doubleの計算結果が異なる

#10

投稿記事 by だんごさん » 10年前

DxLibには既に精度を変えるかどうかの設定ができる関数がありました。
SetUseFPUPreserveFlag( true );
を初期化前に呼び出すことで精度を落とさず、計算結果が正確に出るようになりました。
 Dango San

閉鎖

“C言語何でも質問掲示板” へ戻る