web-dev-qa-db-ja.com

精度の低下-int-> floatまたはdouble

私が修正する試験問題があり、その問題は4点です。

"Java intをdoubleまたはfloatに割り当てることができます。"これにより、情報が失われることはありますか?その理由は?

Intは通常固定長またはサイズであるため、データを格納するための精度は有限であり、浮動小数点に情報を格納することは無限である可能性があるため、本質的に私たちは情報を失います

ここで、ここで正しい領域に到達するかどうかについて、少し大ざっぱです。精度が落ちるのは確かですが、その理由を正確に把握することはできません。手伝ってもらえますか?

26
stan

In Java Integerは、32ビットを使用してその値を表します。

Javaでは、FLOATは23ビットの仮数を使用するため、2 ^ 23より大きい整数は最下位ビットが切り捨てられます。たとえば、33554435(または0x200003)は33554432前後に切り捨てられます+/- 4

Javaの場合、DOUBLEは52ビットの仮数を使用するため、データを失うことなく32ビットの整数を表すことができます。

ウィキペディアの " Floating Point "も参照してください

50
Dead account

浮動小数点数の内部レイアウトを知っている必要はありません。必要なのは、鳩の巣の原理と、intfloatが同じサイズであるという知識です。

  • intは32ビットタイプであり、すべてのビットパターンが個別の整数を表すため、2 ^ 32 int値があります。
  • floatは32ビット型であるため、最大で2 ^ 32の異なる値があります。
  • 一部のfloatsは非整数を表すため、整数を表すfewerよりも2 ^ 32 float値があります。
  • したがって、異なるint値は同じfloat(=精度の低下)に変換されます。

longおよびdoubleでも同様の推論を使用できます。

26
dan04

これは、JLSがこの問題について言っていることです(非技術的な議論の中で)。

JLS 5.1.2拡張プリミティブ変換

プリミティブ型に関する次の19の特定の変換は、拡大プリミティブ変換と呼ばれます。

  • intからlongfloat、またはdouble
  • (残りは省略)

intまたはlong値をfloatに、またはlong値をdoubleに変換すると、精度の低下-つまり、結果は値の最下位ビットの一部を失う可能性があります。この場合、結果の浮動小数点値は、IEEE 754の最も近い丸めモードを使用して、整数値を正しく丸めたバージョンになります。

精度が失われる可能性があるという事実にもかかわらず、プリミティブ型間の変換を広げても、実行時例外は発生しません。

以下は、精度を失う拡大変換の例です。

class Test {
         public static void main(String[] args) {
                int big = 1234567890;
                float approx = big;
                System.out.println(big - (int)approx);
        }
}

印刷する:

-46

したがって、タイプintの値は9桁の有効桁数ではないため、タイプfloatからタイプfloatへの変換中に情報が失われたことを示しています。

19

いいえ、floatdoubleも固定長です。ビットの使用方法が異なるだけです。それらがどのように機能するかについての詳細は Floating-Poing Guide で読んでください。

基本的に、intには52ビットの精度があるため、doubledoubleに割り当てるときに精度を失うことはありません。これは、すべてのint値を保持するのに十分な精度です。 。ただし、floatは23ビットの精度しかないため、約2 ^ 23より大きいすべてのint値を正確に表すことはできません。

14

あなたの直感は正しいです。intfloatに変換すると、精度が失われる可能性があります。ただし、他のほとんどの回答で提示されているほど単純ではありません。

JavaでFLOATは23ビットの仮数を使用するため、2 ^ 23より大きい整数は最下位ビットが切り捨てられます。(このページの投稿から)

真実ではありません。
例:以下は、損失なしで浮動小数点数に変換される2 ^ 23より大きい整数です。

int i = 33_554_430 * 64; // is greater than 2^23 (and also greater than 2^24); i = 2_147_483_520
float f = i;
System.out.println("result: " + (i - (int) f)); // Prints: result: 0
System.out.println("with i:" + i + ",  f:" + f);//Prints: with i:2_147_483_520,  f:2.14748352E9

したがって、2 ^ 23より大きい整数の最下位ビットが切り捨てられるとは限りません。

私が見つけた最高の説明はここにあります:
Javaの浮動小数点は32ビットであり、次のように表されます:
符号*仮数* 2 ^指数
sign *(0〜33_554_431)* 2 ^(-125〜+127)
ソース: http://www.ibm.com/developerworks/Java/library/j-math2/index.html

これはなぜ問題なのですか?
これは、intからfloatへの精度の低下があるかどうかを判断できるという印象を残しますちょうどどのくらい大きいかを見るだけで intです。
私は特にJava試験問題を見てきました。大きなintが損失なしでfloatに変換されるかどうか尋ねられます。

また、intからfloatへの精度が失われると考える人もいます。
intが次の値より大きい場合:1_234_567_890 真ではない(上記の反例を参照)
intが2より大きい場合:2指数23(等しい:8_388_608)not true
intが2より大きい場合:2指数24(等しい:16_777_216)not true

結論
十分に大きな整数から浮動小数点への変換は、精度を失う可能性があります。
lookingだけでは損失が発生するかどうかをintの大きさで判断することはできません(つまり、実際のfloat表現に深く入り込もうとしないで)。

5
Sinkrad

おそらく私が見た中で最も明確な説明: http://www.ibm.com/developerworks/Java/library/j-math2/index.html ULPまたは最小精度の単位は、利用可能な精度を定義します2つのfloat値の間。これらの値が増えると、使用可能な精度が低下します。たとえば、1.0と2.0の間には8,388,609の浮動小数点数があり、1,000,000から1,000,001の間には17があります。10,000,000の場合、ULPは1.0なので、この値を超えると、使用可能な各浮動小数点数に複数の整数値がマッピングされ、精度が失われます。

4
Ian MacMillan

Intをdoubleまたはfloatに割り当てると精度が失われる可能性がある理由は2つあります。

  • Double/floatとして表現できない特定の数値があるため、最終的に近似されます
  • 大きな整数には、リースの有効数字の精度が高すぎる可能性があります
1
Adam Batkin

これらの例では、Javaを使用しています。

このような関数を使用して、intからfloatにキャストするときに精度の低下をチェックします

static boolean checkPrecisionLossToFloat(int val)
{
  if(val < 0)
  {
    val = -val;
  }
  // 8 is the bit-width of the exponent for single-precision
  return Integer.numberOfLeadingZeros(val) + Integer.numberOfTrailingZeros(val) < 8;
}

このような関数を使用して、longからdoubleにキャストするときに精度の損失をチェックします

static boolean checkPrecisionLossToDouble(long val)
{
  if(val < 0)
  {
    val = -val;
  }
  // 11 is the bit-width for the exponent in double-precision
  return Long.numberOfLeadingZeros(val) + Long.numberOfTrailingZeros(val) < 11;
}

このような関数を使用して、longからfloatにキャストするときに精度の低下をチェックします

static boolean checkPrecisionLossToFloat(long val)
{
  if(val < 0)
  {
    val = -val;
  }
  // 8 + 32
  return Long.numberOfLeadingZeros(val) + Long.numberOfTrailingZeros(val) < 40;
}

これらの各関数でtrueを返すと、その整数値を浮動小数点値にキャストすると、精度が失われます。

整数値の有効ビット数が24を超える場合、浮動小数点数にキャストすると精度が低下します。

Doubleにキャストすると、整数値の有効ビット数が53を超えると精度が失われます。

0
HesNotTheStig