- PR -

計算結果があわないです。

投稿者投稿内容
こぶ
会議室デビュー日: 2006/11/14
投稿数: 11
投稿日時: 2007-02-08 10:40
こんにちは
double型どうしの計算を行っているのですが
期待している結果がでません。
下記プログラムを動かした場合、計算結果として
1.2×6なので7.2を期待しているのですが
結果が7.199999999...になってしまいます。

切り上げれば期待する結果にはなるのですが
doubleを使用した場合はこんなものなのでしょうか?

ちなみにJAVAのバージョンはj2sdk1.4.2_13です。

ご存知の方教えてください。よろしくお願いします。

======================
import java.io.*;
class test11
{
public static void main(String args[]) throws IOException
{
double num1 = 1.2;
double num2 = 6;
System.out.println("こんな結果?");
System.out.println("num1 = " + num1 + " num2 = " + num2 + " num9 = " + (double)(num1*num2));

}
}
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-02-08 10:52
引用:

こぶさんの書き込み (2007-02-08 10:40) より:
こんにちは
double型どうしの計算を行っているのですが
期待している結果がでません。
下記プログラムを動かした場合、計算結果として
1.2×6なので7.2を期待しているのですが
結果が7.199999999...になってしまいます。



浮動小数点演算はそんなものです。
十進数による結果を期待したい場合はjava.math.BigDecimalを使いましょう。
Edosson
ぬし
会議室デビュー日: 2004/04/30
投稿数: 675
投稿日時: 2007-02-08 10:58
引用:

こぶさんの書き込み (2007-02-08 10:40) より:

doubleを使用した場合はこんなものなのでしょうか?


こんなもんです。
演算は2進数で行い、結果は10進数で取得する以上、誤差は避けられません。
有効桁数を指定しない演算ロジックは、はっきり言って、無意味です。

「丸め誤差」で検索してみてください。いっぱい出てきますよ。
それにしても、最近の若い人は、習わないんですかね?
Gio
ぬし
会議室デビュー日: 2003/11/28
投稿数: 350
お住まい・勤務地: 都内から横浜の間に少量発生中
投稿日時: 2007-02-08 11:05
引用:

こぶさんの書き込み (2007-02-08 10:40) より:

切り上げれば期待する結果にはなるのですが
doubleを使用した場合はこんなものなのでしょうか?



こんなものです←端折り過ぎ

もう少し正確に書きます。
プログラムテキストでは 1.2 と書いてあっても、内部表現は二進法で 1.0011001…(1 + 1/8 + 1/16 + 1/128 + … に同じ)となっています。
本当は無限に続くのですが、そのままではいくらメモリがあっても足りないので適当なところで切った近似値が使われます。
この値を表示させると確かに 1.2 と出ますが、これも出力時に近似されているためです。
依然として内部表現には誤差があります。

この誤差が拡大されるような計算に使った場合、出力時に近似しきれない結果となることがあります。
こぶさんが書かれたケースがそれです。

正確な演算が必要な場合は、double の代わりに java.math.BigDecimal クラスを使ってみてください。
二進近似をせずに十進のまま、メモリの許す範囲という制限はありますが、小数点以下 100 桁でも 100000000 桁でも指定した精度で数値を扱うことができます。
Edosson
ぬし
会議室デビュー日: 2004/04/30
投稿数: 675
投稿日時: 2007-02-08 11:22
引用:

Gioさんの書き込み (2007-02-08 11:05) より:

こんなものです←端折り過ぎ


だって、詳しく書いたら、きりがないし・・・。
引用:

プログラムテキストでは 1.2 と書いてあっても、内部表現は二進法で 1.0011001…(1 + 1/8 + 1/16 + 1/128 + … に同じ)となっています。


これを、一度でいいから、自分でやってみれば、一発で理解できると思うんですけどね。
引用:

この値を表示させると確かに 1.2 と出ますが、これも出力時に近似されているためです。
依然として内部表現には誤差があります。


ところで、これって「近似された結果」なんですか?
直接代入されたり、ハードコーディングされているリテラル値の場合や、
片方のオペランドが2進化しても誤差がでない数値の場合、
そのように処理されているはずでは。

というか、こういうことも、知らない人が混乱する原因かもしれませんね。

仕様書など当たったわけではないので、確たるものではありませんが、
以下の例の場合、2番目、3番目は「1.2」になりますが、1番目は「1.2」になりません。
System.out.println(0.6f / 0.5);
System.out.println(0.6 / 0.5f);
System.out.println(0.6 / 0.5);
NAO
ぬし
会議室デビュー日: 2001/10/24
投稿数: 1256
お住まい・勤務地: 神奈川のはずれから東京の下町
投稿日時: 2007-02-08 11:29
引用:

Edossonさんの書き込み (2007-02-08 11:22) より:
引用:

Gioさんの書き込み (2007-02-08 11:05) より:

こんなものです←端折り過ぎ


だって、詳しく書いたら、きりがないし・・・。
引用:

プログラムテキストでは 1.2 と書いてあっても、内部表現は二進法で 1.0011001…(1 + 1/8 + 1/16 + 1/128 + … に同じ)となっています。


これを、一度でいいから、自分でやってみれば、一発で理解できると思うんですけどね。
引用:

この値を表示させると確かに 1.2 と出ますが、これも出力時に近似されているためです。
依然として内部表現には誤差があります。


ところで、これって「近似された結果」なんですか?
直接代入されたり、ハードコーディングされているリテラル値の場合や、
片方のオペランドが2進化しても誤差がでない数値の場合、
そのように処理されているはずでは。

というか、こういうことも、知らない人が混乱する原因かもしれませんね。

仕様書など当たったわけではないので、確たるものではありませんが、
以下の例の場合、2番目、3番目は「1.2」になりますが、1番目は「1.2」になりません。
System.out.println(0.6f / 0.5);
System.out.println(0.6 / 0.5f);
System.out.println(0.6 / 0.5);



要するに抜本的な所を教えないからでしょうね。
CPUの世界というかビットというかデジタルというか電圧の世界では
0か1しか無いって事を教えてないから

こういう質問が上がってくるんでしょうね。 
Edosson
ぬし
会議室デビュー日: 2004/04/30
投稿数: 675
投稿日時: 2007-02-08 12:02
引用:

NAOさんの書き込み (2007-02-08 11:29) より:

要するに抜本的な所を教えないからでしょうね。
CPUの世界というかビットというかデジタルというか電圧の世界では
0か1しか無いって事を教えてないから

こういう質問が上がってくるんでしょうね。 


私のことですか? σ(・・)
お手数をおかけしますが、具体的に指摘して頂けましたら、ありがたいであります。
杏仁豆腐
常連さん
会議室デビュー日: 2003/10/04
投稿数: 48
お住まい・勤務地: あっち・なぜか平和だったところ(T_T)
投稿日時: 2007-02-08 12:33
引用:

Edossonさんの書き込み (2007-02-08 10:58) より:
それにしても、最近の若い人は、習わないんですかね?


習わない人のほうが多いだろうなぁって思いますね。
このことに限らず体系的な教育は作業ができる最小限で
あとは、問題に直面したときに教えるってのが大半だと思います。

COBOLメインだった目上の方も、こんなもん?って感じでしたよ。
COBOLではそういうことは気にしなくていいと言っていましたが、
そうなんですか?

COBOL入門のサイトをいくつか見てみて、そうらしいとは思ったんですが
確信は得られませんでした。

スキルアップ/キャリアアップ(JOB@IT)