doubleに割り当てたときに2つのintを除算すると正しい値が得られないのはなぜですか?


110

次のスニペットでどうして

int a = 7;
int b = 3;
double c = 0;
c = a / b;

c予想通り、2.3333ではなく2になります。場合abダブルスあり、答えは2.333に変わりはありません。しかし、確かにc すでにdoubleであるため、整数で動作するはずでしたか?

では、どうしてint/int=doubleうまくいかないのですか?


回答:


161

これは、整数除算バージョンのを使用しているためです。operator/これは2 int秒かかり、を返しますintdoubleを返すバージョンを使用するには、double少なくとも1つのをint明示的ににキャストする必要がありますdouble

c = a/(double)b;

9
私は明示的に両方を変換することを好むabdouble明確にするため、単純に、それは本当に問題ではありません。
John Dibling 2011

31
質問にはC ++のタグが付いているので、Cキャストではなくstatic_cast <>を表示したいと思います。
マーティンヨーク

16
個人的には、Cスタイルのキャストの方がわかりやすいと思います(他のほとんどの一般的な言語でのキャストはCスタイルの方法で行われます)。 static_cast<>いつも私には長い間、うんざりしていた。プリミティブの場合は、実際に得ることの危険性がないstatic_cast<>reinterpret_cast<>ミックスアップ。
ガーディア

6
@ Tux-D:算術キャストの場合?static_castこの場合は避けて、代わりにCスタイルのキャストを使用したいと思います。ここでC ++スタイルのキャストを使用してもメリットはなく、Cスタイルのキャストよりもコードが煩雑になります。算術キャストは、Cスタイルのキャストが完全に適切であり、実際には他のキャストよりも適切なコンテキストです。
AnT 2009

19
時には、「Cスタイルキャストなし」の人々の裏をかくことができますdouble(b)。明示的なコンストラクター呼び出しと同じように見えるため、変換であるとは必ずしも認識しません。
Steve Jessop

12

ここにあります:

a)2つintのsを除算すると、常に整数除算が実行されます。したがって、a/bあなたの場合の結果は、intます。

を保持abints として完全に分割する場合は、少なくとも1つをdoubleにキャストする必要があります:(double)a/bまたはa/(double)bまたは(double)a/(double)b

B)cであるdoubleことができるので、受け入れますint:assignementに値をint自動的に変換されdouble且つに割り当てられましたc

c)代入時に、の右側の式が最初に=計算され(上記の規則(a)に従って、かつの左側の変数に関係なく)、次に(に従って)の左側の変数に割り当てられるb)上記)。これで全体像は完成したと思います。==


11

非常に少数の例外を除いて(1つしか考えられません)、C ++は式自体から式(または部分式)の全体的な意味を決定します。式の結果をどのように処理するかは重要ではありません。あなたの場合、式a / bdoubleは見えません。すべてですint。したがって、コンパイラは整数除算を使用します。結果が得られると、それをどうするかを検討し、に変換しdoubleます。


3
私が考えることができる1つの例外は、ポインタを取るときに関数のオーバーロードを選択することです-の値は、&funcnameキャストする型によって異なります。
Steve Jessop

2
@Steve Jessopそれも私が考えられる唯一の例外です。(しかし、標準のサイズと複雑さを考えると、私が見逃していないことを誓いたくありません。)
James

6

cdouble変数ですが、それに割り当てられるint値は2つintのsの除算から得られる値であり、これにより「整数除算」が行われます(残りは削除されます)。だから行で何が起こるかc=a/bです

  1. a/b 評価され、タイプの一時ファイルが作成されます int
  2. 一時変数の値は、ctypeへの変換後に割り当てられdoubleます。

の値はa/b、そのコンテキスト(への割り当てdouble)を参照せずに決定されます。


6

2つの整数を除算すると、doubleに格納するかどうかに関係なく、結果は整数になります。


5

C ++言語では、subexpresisonの結果が周囲のコンテキストに影響されることはありません(まれな例外はあります)。これは、言語が注意深く従う原則の1つです。式にc = a / b含まれている独立した部分式はa / b、その部分式の外にあるものからは独立して解釈されます。言語は、後で結果をに割り当てることを気にしませんdoublea / b整数除算です。他は何でも構いません。言語仕様の多くのコーナーでこの原則が守られていることがわかります。これは、C ++(およびC)がどのように機能するかを示しています。

上で述べた例外の1つの例は、関数のオーバーロードを伴う状況での関数ポインターの割り当て/初期化です。

void foo(int);
void foo(double);

void (*p)(double) = &foo; // automatically selects `foo(fouble)`

これは、割り当て/初期化の左側が右側の動作に影響する1つのコンテキストです。(また、配列への参照の初期化により、同様の動作の別の例である配列型の減衰が防止されます。)他のすべての場合では、右側は左側を完全に無視します。


4

/オペレータは、整数除算や浮動小数点除算のために使用することができます。あなたはそれに2つの整数オペランドを与えているので、整数除算を行っており、結果はdoubleに格納されています。


2

これは技術的には言語に依存しますが、ほとんどすべての言語でこの主題は同じように扱われます。式の2つのデータ型の間に型の不一致がある場合、ほとんどの言語は=、事前定義された一連のルールに従って、一方の側のデータをキャストして、もう一方の側のデータと一致させようとします。

同じ型の2つの数値(整数、倍精度など)を除算すると、結果は常に同じ型になります(したがって、「int / int」は常にintになります)。

この場合、計算後にdouble var = integer result 整数の結果をdouble キャストします。この場合 、小数データは既に失われています。(ほとんどの言語は、このキャストを行って、例外やエラーを発生させずに型の不正確さを防ぎます)。

結果を2倍にしたい場合は、次のような状況を作りたいと思うでしょう。 double var = double result

これを行う最も簡単な方法は、方程式の右辺の式を強制的に2倍にキャストすることです。

c = a/(double)b

整数とdoubleを除算すると、整数がdoubleにキャストされます(計算を行う場合、コンパイラーはデータ損失を防ぐために、最も具体的なデータ型に「アップキャスト」することが多いことに注意してください)。

aアップキャストの後、ダブルとして巻き上げられ、今、あなたは2つのダブルの間の分割を持っています。これにより、目的の部門と割り当てが作成されます。

再び、これは言語固有であることに注意してください(ただし、コンパイラ固有でもかまいません)。ただし、ほとんどすべての言語(確かに頭の中で考えられるすべての言語)がこの例を同じように扱います。


この質問には[C ++]というタグが付けられており、C ++標準ではこれがどのように機能するかを正確に規定しています。「言語固有」が何を意味するのかわからず、コンパイラー拡張機能が使用されていない場合は、コンパイラー固有ではありません。
John Dibling 2011

また、「double var = double varをintにキャストする整数の結果」と言うのは誤りです。doubleはintにキャストされません。intの結果はdoubleに変換されます。
John Dibling 2011

私はコンパイラー拡張機能の可能性を考慮していました(環境で結果が「誤ってキャストされた」ため、この問題を一度経験したことがあり、その理由を理解できませんでした)。また、一部の言語では同じキャスト規則に従っていないため、結果は言語固有です。C ++固有のタグだとは思わなかった。「double var = integer result」というコメントは正しい。それを反映するように編集されました。ありがとうございました!
matthewdunnam 2011

0

重要なのは、計算の要素の1つがfloat-double型であることです。次に、二重の結果を取得するには、次のようにこの要素をキャストする必要があります。

c = static_cast<double>(a) / b;

またはc = a / static_cast(b);

または、直接作成することもできます::

c = 7.0 / 3;

float-double型の整数による除算を示すには、計算の要素の1つに「.0」が必要であることに注意してください。そうでなければ、c変数がdoubleであるにもかかわらず、結果もゼロになります。


他の9つの回答のいずれもまだ存在していないということで、あなたの回答は何をもたらしますか?
bolov
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.