- - PR -
時間を表示/バグについて
| 投稿者 | 投稿内容 | ||||
|---|---|---|---|---|---|
|
投稿日時: 2002-07-24 21:18
C言語の説明をして頂いた方もいますが、私はC言語が専門ではありませんのでよく分かりません。申し訳ありません。皆さんの意見を見ますと、結論としては「バグではない」という感じですね。まだ納得がいかないので誰か教えて下さい。
プログラムの中でやったのは84 / 0.7のような計算をdouble型でして、それをMath.ceil()で切り上げするというものでした。こうすると120ではなく121になってしまうので質問させてもらったわけです。対策としてはdouble型をfloat型に変換して小数点以下の桁数を減らすことで解決しました。私の作ったCのプログラムでは… #include <stdio.h> void main() { int a = 84; double b = 0.7; double c = a / b; printf("%.30f\n",c); } のように作りました。Ultra-C Pro Version 2.0 このように小数点以下の桁数をいくら増やしても、Javaのように120.00……01の1は出てきません。 Javaでの対策案は皆さんの通りいろいろな方法があるとは思います。10進浮動小数を、IEEE 浮動小数点形式等の2進表現に誤差なく完全には変換出来ないというのも十分分かります。しかし私が申し上げたいのはCコンパイラに出来てJavaコンパイラに出来ないというのは、やはりバグだと思うのですがどうでしょう。 | ||||
|
投稿日時: 2002-07-24 22:23
あらゆるCあるいはC++コンパイラでjackさんの提示された結果になるのであれば
バグといえないこともないかもしれません。 Ultra-C Pro Ver2.0(マイナー) の結果で議論するのは間違っています。 Ultra-C Pro Ver2.0が生成した実行ファイルが何らかのアドホック(場当たり的)な コードを含んでいるのかもしれません。 mikiさんが示されているようにgccではJAVAと同じ結果になります。 "コンパイラの実装云々でバグだ"と言いたいのなら、少なくとも メジャーなコンパイラ全ての結果を提示しましょう! ちなみにJavaコンパイラ(javac)はバイトコードを生成しているだけです。 実際の実行はJavaバイトコードインタープリタ(java)で行います。 "84/0.7"を実際に演算しているのは"javac"ではなく"java"です。 | ||||
|
投稿日時: 2002-07-24 22:34
ありがとうございました。ようやく納得です。
| ||||
|
投稿日時: 2002-07-26 00:16
C言語も、objectさん様の言われるように、小数点以下を
2進数で表現しきれない為 84/0.7は119.999999999の近似値になります。 ただ、C言語のprintfの%fは、表示桁より下位桁を 四捨五入してから表示している為120と正確な値を 表示します。 未確認ですが、printfの四捨五入は仕様だと思われます。 | ||||
|
投稿日時: 2002-07-26 10:57
私も最近小数点部分の誤差の問題にぶつかりました。
調べると、どうやらこれはコンピュータで処理する以上しょうがないようです。 詳しくは、下を。 http://www.geocities.co.jp/SiliconValley/4334/unibon/topic/radixerror.html | ||||
|
投稿日時: 2002-07-26 11:37
>あらゆるCあるいはC++コンパイラでjackさんの提示された結果になるのであれば
>バグといえないこともないかもしれません。 もともとはjavaのバグか、という疑問から始まっているスレッドです。 JavaのバグということはJavaの仕様に反しているということですね。 C言語の仕様上常にdoubleを64ビットで計算することが保証されているのでしょうか。プロセッサやコンパイラの仕様によってCコンパイラの挙動が異なるとしたら、Javaと比較すること自体なんら意味がありません。少なくとも、C言語ではint型が何ビットであるかはプロセッサによってまちまちですよね。 両方の言語の計算結果が一緒だから、Javaの仕様に合っているということも保証できません。 だって、両方とも計算が間違っている可能性だってあるじゃないですか。たとえば、あるJVMの実装がC言語のライブラリをつかっていて、それがバグを持っていたために両方が同じ間違った計算結果を返していた、ということもあるかもしれません。 だから、Javaのバグと言いたいのであれば、Java仮想マシン仕様書が定める浮動小数点演算の方法にしたがって84/0.7の理想の計算結果を求め、それが実際のSunのJavaの実装と違っているということを証明できればよいのだと思います。 | ||||
|
投稿日時: 2002-07-26 12:28
jackさんのいっている"Javaのバグ"は"JAVA仮想マシン実装上のバグ"ではなく "JAVA言語仕様上のバグ"のような気がします。 jackさんが特定のCコンパイラ実装のみをみて"Javaのバグ"といっているので 「他の実装ではどうか?」と前回の投稿では提示しています。 ISOの"C言語仕様"あるいは"C++言語仕様"と"JAVA言語仕様"を比較するという類の はなしです、たぶん。 [ メッセージ編集済み 編集者: asip 編集日時 2002-07-26 17:35 ] | ||||
|
投稿日時: 2002-07-26 13:18
問題にしない方が良いかなと思ったのですが、敢えて書きます。
この問題は、いくつかの問題を含んでいるので、整理した方が良いように思います。 それで、みなさんは問題にしていませんが、私には大きいと思える問題を書きます。 jackさんは、 「同じ事をC言語でやるとうまくいくのでJavaコンパイラの計算機ルーチンによるバグだと思われる」 とおっしゃってますよね。 つまり、10進数の計算が、C言語ではそのまま計算されていると判断していると思います。 私は、ここに一つ大きな間違いがあると思って、10進数と2進数の関係、特に浮動小数(有理数)の問題を指摘したわけです。 でも、実は、有理数の場合、10進数でも基本的には同じ問題があるんです。 有理数ですから、当然一般的には、どこかの桁で丸めざるを得ない訳です。 丸めに関する処理は、大学程度の物理実験を経験された方は、知っていると思いますが、乗除の場合、最小の有効数字で精度が決まってしまいます。 今回の場合 int a = 84; double b = 0.7; ですから、ハッキリ言えば、「b」の有効数字は、「7」1個です。(実際の有効数字は分かりません。) つまり、結果で信頼出来るのは、c = 120.0000000000000の「1」だけです。 具体的に言えば、 110 < c < 130 なんです。 だから、 「c = 120.0000000000000」を問題にする事に問題がある、と私は考えました。 つまり、プログラムで処理をすべき内容の曖昧さが、今回の問題なのではないでしょうか? みなさんは、どう思いますか? (念の為、Javaのバグを問題にする事が悪いと言っている訳ではありません。) | ||||
