無題

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
fumi

無題

#1

投稿記事 by fumi » 16年前

こんばんは。
今回、異なるデータ型の計算で疑問に思ったことがあるので投稿致します。

事の発端は、物理シュミレーションで投げ上げを再現しようとしていたことにあります。
しかし、うまく動かず、原因がデータ型の異なる計算にあること(恐らく)までは発見しました。
ミスを再現したプログラムが以下になります。
#include <stdio.h>
#include <math.h>

void main()
{
	int v0=-20;
    unsigned int nowcnt=300;
	double g=2.3333333;
	printf("%f",v0*nowcnt+g*pow(double(nowcnt), 2.0)/2);
}
これを実行しますと、出力がえらいことになります。
これを、

printf("%f",v0*(int)nowcnt+g*pow(double(nowcnt), 2.0)/2);

としますと、正しい出力が得られました。v0を、
v0=20;
と正値にしても正しい結果が得られました。
ミスは恐らく、unsigned int型とint型(値は負)を乗算しているからだと思うのですが、正しいでしょうか?
また、この手のことはコンパイラに依存することなのでしょうか?(ちなみに、コンパイラは警告しませんでした。)
つまるところ、解決法はわかったが、原因がよくわかっていない状態です。

どうか、ご教授お願いします。

環境は、Visual C++ 2005 Express Editionです。

fumi

Re:無題

#2

投稿記事 by fumi » 16年前

すみません。タイトルを入れ忘れてしまいました。m(_ _)m

ibis

Re:無題

#3

投稿記事 by ibis » 16年前

なんでしょねぇ。
この場合なら暗黙的にintに変換されて、int同士の乗算になるはずなんですが。

多分関係ないですが、doubleのキャストは必要無いかと思います。

ところで、「出力がえらいことに」ってのと「正しい結果」はそれぞれどんな値ですか?

box

Re:無題

#4

投稿記事 by box » 16年前

> この場合なら暗黙的にintに変換されて、int同士の乗算になるはずなんですが。

そうなんですか?
私は、unsigned int型とint型の演算を行なうと、int型がunsigned int型に
変換されると思っていました。
sizeof(int)やsizeof(unsigned int)が4である場合、
int型の-20(0xffffffec)をunsigned int型とみなした結果4294967276となり、
それに300を掛けるとunsigned int型で表わせる範囲を超えてしまい、
下位のsizeof(unsigned int)バイトを取って4294961296となり、
本来ほしかったはずの-6000とは似ても似つかない結果となります。

fumi

Re:無題

#5

投稿記事 by fumi » 16年前

ibisさん、boxさん、ご回答ありがとうございます。

>ibisさん
わかりにくい表現で申し訳ないです。
「えらいことに」の値は「4295066295.998500」でした。
一方、「正しい結果」の値は「110999.998500」でした。
double型にキャストしていたのは、pow()がdouble型しか引数にとれないと思い込んでいたためですorz。
今まで、pow()の第1、2引数に両方int型を与えると、コンパイルに警告がでていましたので…
実際に、第1引数のキャストを外してみても、警告は出ませんでした。
ご指摘ありがとうございます。

>boxさん
わかりやすい解説ありがとうございます。
私もint型とunsigned int型を乗算した場合、暗黙的にint型にキャストされるだろうと勘違いしていたようです。
int型の負値が2の補数表現で表すため、unsigned int型にキャストされると、思ってもみない大きな値になってしまう、ということでよろしいでしょうか?

fumi

Re:無題

#6

投稿記事 by fumi » 16年前

すみません、ibisさんへの返答の追記です。
「正しい結果」の上記の値は、v0=20としたとき正しく計算されている、ということであり、
希望であった(冒頭のプログラムの)v0=-20のときの正しい値は、「98999.998500」でした。

ibis

Re:無題

#7

投稿記事 by ibis » 16年前

>unsigned int型とint型の演算を行なうと、int型がunsigned int型に変換される
あ、すみません、unsigned intに変換されますね。
勘違いでした。

>double
暗黙の変換でdouble型として扱われる、という意味です。
片方の引数がdoubleなら、他方はintでも大丈夫なんですよ。
わかりにくくてすみませんでした。

fumi

Re:無題

#8

投稿記事 by fumi » 16年前

>ibisさん
それは初耳でした。
暗黙的な変換って便利なのかもしれませんけど、わかりにくい一面がありますよね…
勉強になりました。ありがとうございます!

閉鎖

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