a=b=cになるよう代入したのにa≠cになってしまったJavaTips 〜Javaプログラミング編

» 2006年08月02日 10時00分 公開
[平野正喜@IT]

 一般に、変数aから変数bに代入すると、この2つの変数の値が等しくなり、変数bから変数cに代入すると、変数bと変数cの値が等しく、変数aと変数cの値も等しくなります。

 変数の型が違う場合も、基本的には同様です。変数aとCが整数のint型で、変数bが実数のdouble型であれば、下記の例のように、変数aから変数bに代入すると「暗黙の型変換」が行われて、この2つの変数の値が等しくなり、変数bから変数cにキャストしつつ代入すると、変数bと変数cの値が等しく、変数aと変数cの値も等しくなります。

画面1 int型→double型→int型の場合 画面1 int型→double型→int型の場合

 しかし、ここでdouble型をfloat型に変更すると、最後の比較が成立しなくなります。つまり、変数a→変数bの代入では「暗黙の型変換」が行われ、2つの変数の値が等しくなり、変数bをキャストして変数cに代入すると変数bと変数cが等しくなるところまでは、double型の場合と同じですが、変数aと変数cの値は等しくならないのです。これはどういうことでしょうか。

画面2 int型→float型→int型の場合 画面2 int型→float型→int型の場合

比較演算は「暗黙の型変換」後に行われるので誤差が無視される

 この現象が起こる原因は、「==」記号を用いた比較が、実際には比較演算という一種の演算であり、型の違う値を用いる場合には、他の演算と同様に「暗黙の型変換」が事前に行われることにあります。

 上記の「int型→float型→int型の場合」の結果を見ての通り、有効桁数が少ないfloat型に変数aの「123,456,789」という大きなint型の値を代入すると、有効桁数不足から誤差が発生します。その結果が変数bの「1.23456792×10の8乗」という値です。その後で、変数aとbを比較するときには、「暗黙の型変換」により、変数aの「123,456,789」が「1.23456792×10の8乗」に内部的に変換されます。この変換結果と変数bの値は等しいので、「a == b」となるわけです。

 また、変数bの「1.23456792×10の8乗」という値をint型にキャストすると「123,456,792」となり、これを変数cに代入しているわけですが、変数bとcを比較するときには、「暗黙の型変換」により、変数cの「123,456,792」が「1.23456792×10の8乗」に内部的に変換されます。この変換結果と変数bの値は等しいので、「b == c」となるわけです。

 つまり、誤差の発生により、変数aの「123,456,789」も変数cの「123,456,792」も、float型に変換すると同じ「1.23456792×10の8乗」になってしまうのです。しかし、int型どうしの「123,456,789」と「123,456,792」は当然等しくなりません。よって「a=b=cなのにa≠cとなる」という現象が起こるわけです。

 ちなみに、下記のように試すとわかりますが、int型の「123,456,789」から「123,456,795」までが、float型の「1.23456792×10の8乗」と等しいとみなされます。

画面3 「1.23456792×10の8乗」と等しいint型の値は? 画面3 「1.23456792×10の8乗」と等しいint型の値は?

 int型とfloat型間の代入では誤差の発生が付き物です。しかも、コンパイルエラーにはなりませんし、例外も発生しません。このことを忘れると、もっと複雑で解決の難しいトラブルが起こる場合がありますので、注意すべきです。

Profile

RunDog.org

平野正喜


Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。