私が修正する試験問題があり、その問題は4点です。
"Java intをdoubleまたはfloatに割り当てることができます。"これにより、情報が失われることはありますか?その理由は?
Intは通常固定長またはサイズであるため、データを格納するための精度は有限であり、浮動小数点に情報を格納することは無限である可能性があるため、本質的に私たちは情報を失います
ここで、ここで正しい領域に到達するかどうかについて、少し大ざっぱです。精度が落ちるのは確かですが、その理由を正確に把握することはできません。手伝ってもらえますか?
In Java Integerは、32ビットを使用してその値を表します。
Javaでは、FLOATは23ビットの仮数を使用するため、2 ^ 23より大きい整数は最下位ビットが切り捨てられます。たとえば、33554435(または0x200003)は33554432前後に切り捨てられます+/- 4
Javaの場合、DOUBLEは52ビットの仮数を使用するため、データを失うことなく32ビットの整数を表すことができます。
ウィキペディアの " Floating Point "も参照してください
浮動小数点数の内部レイアウトを知っている必要はありません。必要なのは、鳩の巣の原理と、int
とfloat
が同じサイズであるという知識です。
int
は32ビットタイプであり、すべてのビットパターンが個別の整数を表すため、2 ^ 32 int
値があります。float
は32ビット型であるため、最大で2 ^ 32の異なる値があります。float
sは非整数を表すため、整数を表すfewerよりも2 ^ 32 float
値があります。int
値は同じfloat
(=精度の低下)に変換されます。long
およびdouble
でも同様の推論を使用できます。
これは、JLSがこの問題について言っていることです(非技術的な議論の中で)。
プリミティブ型に関する次の19の特定の変換は、拡大プリミティブ変換と呼ばれます。
int
からlong
、float
、または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
への変換中に情報が失われたことを示しています。
いいえ、float
とdouble
も固定長です。ビットの使用方法が異なるだけです。それらがどのように機能するかについての詳細は Floating-Poing Guide で読んでください。
基本的に、int
には52ビットの精度があるため、double
をdouble
に割り当てるときに精度を失うことはありません。これは、すべてのint
値を保持するのに十分な精度です。 。ただし、float
は23ビットの精度しかないため、約2 ^ 23より大きいすべてのint
値を正確に表すことはできません。
あなたの直感は正しいです。int
をfloat
に変換すると、精度が失われる可能性があります。ただし、他のほとんどの回答で提示されているほど単純ではありません。
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表現に深く入り込もうとしないで)。
おそらく私が見た中で最も明確な説明: 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なので、この値を超えると、使用可能な各浮動小数点数に複数の整数値がマッピングされ、精度が失われます。
Intをdoubleまたはfloatに割り当てると精度が失われる可能性がある理由は2つあります。
これらの例では、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を超えると精度が失われます。