算術式は、ゼロの代わりに6.135157E-6を計算します

私はアプリのどこかに以下のコードを持っています

float private myMethod(float c){
    result = (float) (c+273.15);
}

"c"が-273.1455のような値を取得すると、結果は0.0044のようにゼロに非常に近くなります。

しかし、値-273.15を得ると、ゼロの代わりにこれが得られます:6.1035157E-6

なぜこれが起こるのですか?

2
...そして多くの他の質問(それについて話していますが、私たちが最もよく聞かれる質問のFAQを維持する方法はありますか?モデレータと他の人がそれらを見つけるために使用するようにあまりユーザーにはありません)。
追加された 著者 Jason S,
@miako - 絶対に - それはあなたの批判ではありません。あなたの質問が閉鎖されている(私はそれがすべきであると思う)場合、それは否定的なことではない、それはこのウェブサイトのためのただのコンベンションです:私たちは他の質問の重複として質問をマークします。同じ話題。
追加された 著者 Jason S,
私はこの関数の呼び出しの前にあなたのcの計算に何か間違っていると思います。
追加された 著者 Yury,
これは浮動小数点演算の結果によって異なります。 result =(float)(-273.15 + 273.15)を使用すると、コンパイル時の最適化になりますので、ゼロになります。 (float)(c + 273.15)はCPUの浮動小数点命令を使用しますが、そのような小さな誤差が生じます。必要な精度を使用するためにいくつかの数学関数を使用することができます。
追加された 著者 Karthik,
6.1035157E-6は0.0044よりもゼロに近くなっていませんか?
追加された 著者 Karthik,
@ JasonS私はあなたのポイントを参照してください。私はここに新しいので、私はそれがどのようにうまく動作しているかわかりません。あなたが正しいです、それは重複が存在する時を指摘するのは良いことです。今私は自分の質問のタイトルが良いではないことを知っている誰かが彼が探している主題であるかどうかを見つけることは容易ではないので。
追加された 著者 tioschi,
@ JasonS時々あなたは質問をしますが、答えについての手がかりはありません。私はこの質問をしたとき、私は浮動小数点演算と関係があるとは知らなかった。だからどのような種類の話題を探しているのですか?したがって、複製が存在することは避けられません。
追加された 著者 tioschi,
@ Yury、デバッグモードでは、myMethodにパラメータとして渡されるとき、cは-273.15であることがわかります。だから私はなぜそれが起こるか見ることができません
追加された 著者 tioschi,
@ Karthik、そうですが、私はこの値をユーザーに出力して欲しいです。したがって、これの代わりに0を表示する方が良いです。また、コードをresult =(float)(-273.15 + 273.15)に変更すると、ゼロになります。それは奇妙ではないですか?
追加された 著者 tioschi,

3 答え

問題は、273.15が浮動小数点ではなく二重であり、どちらも正確に273.15を表すことができないということです。しかし、彼らは異なる精度を持っているので、実際には丸くなり、異なる数を格納します。加算が行われると、cは倍精度に変換され、273.15のfloat表現を格納することができます。これで、ほぼ同じ値を持つ2つのdoubleが得られ、その差はゼロではありません。

「より予測可能な」結果を得るには、273.15fを使用して計算を浮かべてください。これはこの問題を解決するはずですが、実行する必要があるのは、バイナリ浮動小数点算術演算子を読み込み、それが学校で教えられている小数演算とどのように違うのかを読み取ることです。

Wiki on floating point is a good place to start.

6
追加された
@miako - Rogerは(c + 273.15)というコードのリテラルを参照しています。小数点を含むリテラルは、最終的にはFではなく、コンパイラによって double として理解されます。
追加された 著者 Dawood ibn Kareem,
+1。 273.15は浮動小数点で正確に表現することができないので、 double 表現は float 表現よりも正確でなければなりません。この質問は、リテラルのタイプが作ることができる違いの大きな実例です。
追加された 著者 Dawood ibn Kareem,
はい、浮動小数点演算でsthを実行する必要があります。しかし、私はこの in_text = Float.parseFloat(etOne.getText()。toString())のような変数を入力します。 tvOne.setText(float.toString(myMethod(in_text、d))); 浮動小数点ではなく二重になるのはなぜですか?
追加された 著者 tioschi,
@DavidWallaceそして、その問題を解決しました。正しい。私は本当にこれについて読むべきです。良い投稿があれば教えてください。ありがとうございました
追加された 著者 tioschi,
Roger Lindsjoに感謝します。
追加された 著者 tioschi,

コンピュータの浮動小数点計算は正確ではありません。このようなエラーを防ぐために、浮動小数点演算について何かお読みください。

2
追加された
だから誰もが言っているように浮動小数点演算を使っています。私はこれらの問題について以前は知らなかった。
追加された 著者 tioschi,

問題は値ではなく、ユーザーに表示されます。

私はあなたがそれを文字列に変換していると仮定しています。これが行われる方法は、 http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Double.html#toString(double

To Display a correct value use the NumberFormat class http://docs.oracle.com/javase/1.4.2/docs/api/java/text/NumberFormat.html

例:

NumberFormat formater = NumberFormat.getNumberInstance()
formatter.setMaximumFractionDigits(4);
formater.format(myMethod(-273.15))

今度は0になるはずです。

0
追加された
ハードコード273.15fの場合は、あなたは正しいです。しかし、ほとんどの場合、それはハードコーディングされた値ではなく、ある算術演算から来ます。コンパイラが加算/減算/乗算/文字列変換を最適化する方法は、不正確になる可能性があります。
追加された 著者 Chip,
実際には、すべての浮動小数点数をバイナリ表現で「正確に」表すことはできません。これがどのように行われたかを読むことができます。しかし、主なポイントは、273.15を書く場合、絶対に正確に表すことができないため、273.15000004252または273.15000023623(例のみ)として保存することができます。だから減算すれば、2.4263E-8になるかもしれません。これは単なる浮動小数点計算の性質です。
追加された 著者 Chip,
あなたが273.15Fを持っていても、0であることは保証されていません。コンパイラの最適化は、0以外の何かにするかもしれません。
追加された 著者 Chip,
私はロジャー・リンドジョが言ったようにして、それがうまくいった。正しいコードは result =(float)(c-273.15F); であり、機能しました。明示的に浮動小数点数を書くことなく10進数を書くと、システムによってデフォルトでは2倍になります。しかし、私は別の問題のためにあなたの情報が必要になるでしょう。私はNumberFormatクラスが必要になります。
追加された 著者 tioschi,
何故ですか?両方の値は浮動小数点であり、同じ数値の完全に同じ表現をしています。だから私はそれがゼロにしかならないと思います。
追加された 著者 tioschi,
浮動小数点システムは、正確か否かにかかわらず常に同じ方法を表現します。違いは、32ビット(float)または64ビット(double)を選択した場合です。浮動小数点数の異なる表現は、浮動小数点数を宣言するのではなく、浮動小数点数から浮動小数点数にキャストするときに来ると思います。
追加された 著者 tioschi,