回答:
Java double
はIEEE-754形式であるため、52ビットの端数があります。したがって、2つの隣接する2の累乗(1を含み、次の1をdouble
除く)の間には、2から52の累乗の異なるs(つまり、4503599627370496)があります。たとえば、これdouble
は0.5が含まれていることと1.0が除外されていることの明確なsの数であり、その多くは含まれている1.0と2.0が除外されていることも同様です。
doubles
0.0と1.0 の間を数えることは、2のべき乗の間で行うよりも、その範囲に含まれる2のべき乗が多く、非正規化数の厄介な問題に遭遇するため、困難です。指数の11ビットの10が問題の範囲をカバーしているので、非正規化数(および私はいくつかの種類のものを含むNaN
)を使用するとdouble
、2のべき乗の間に1024倍のsが存在します- 2**62
とにかく全体で。非正規化された&cを除いて、数は1023倍になると思います2**52
。
「100〜100.1」のような任意の範囲の場合、上限をaとして正確に表すことができないためdouble
(2の累乗の正確な倍数ではないため)、さらに困難になります。便利な近似として、2の累乗間の進行は線形であるため、この範囲は0.1 / 64
周囲の2の累乗(64と128)の間のスパンのthであると言えます。
(0.1 / 64) * 2**52
明確なdouble
s-これは7036874417766.4004
... 1つまたは2つを与えるか取る;-)。
2**64
可能なdouble値は(64ビット型であるため)あり得ず、それらの値の非常に大きな比率は0..1
どうですか?
double
表現が間0x0000000000000000
に0x3ff0000000000000
あり、区間[0.0、1.0]内にあるすべての値。これは(2 ^ 62-2 ^ 52)の異なる値です(エンドポイントをカウントするかどうかに応じて、プラスまたはマイナスのカップル)。
区間[1.0、2.0]の間の表現に対応する0x3ff0000000000000
と0x400000000000000
、それは2 ^ 52の異なる値です。
間隔[100.0、101.0]は、0x4059000000000000
との間の表現に対応し0x4059400000000000
ます。それは2 ^ 46の異なる値です。
10 ^ 100と10 ^ 100 + 1の間には倍数はありません。これらの数値のどちらも倍精度で表現できず、それらの間にある倍精度はありません。最も近い2つの倍精度数は次のとおりです。
99999999999999982163600188718701095...
そして
10000000000000000159028911097599180...
[0.0、1.0]の範囲に約2 ^ 62の倍数があることをすでに説明している人もいます。
(本当に驚くべきことではない:ほとんどの2 ^ 64の異なる有限のダブルスがあり、これらのうち、半分は正であり、そして約半分のものを <1.0です。)
しかし、乱数ジェネレータについて言及します。0.0と1.0の間の数を生成する乱数ジェネレータは、一般にこれらのすべての数を生成できるわけではないことに注意してください。通常、n / 2整数のn / 2 ^ 53の形式の数値のみを生成します(たとえば、nextDoubleの Javaドキュメントを参照)。そのため、random()
出力には通常、約2 ^ 53(含まれるエンドポイントに応じて+/- 1)の可能な値しかありません。つまり、[0.0、1.0]のほとんどのdoubleは生成されません。
記事Javaの新しい数学、パート2: IBMからの浮動小数点数は、これを解決するために次のコードスニペットを提供します(floatでですが、doubleでも機能すると思われます)。
public class FloatCounter {
public static void main(String[] args) {
float x = 1.0F;
int numFloats = 0;
while (x <= 2.0) {
numFloats++;
System.out.println(x);
x = Math.nextUp(x);
}
System.out.println(numFloats);
}
}
彼らはそれについてこのコメントを持っています:
1.0と2.0の間には正確に8,388,609の浮動小数点数があることがわかります。この範囲に存在する実数の数え切れないほどの無限大はほとんどありません。連続する数値は約0.0000001離れています。この距離は、精度が最も低い単位または最後の単位のULPと呼ばれます。
float
、ではない double
- float
sが、その端数の23ビット分に相当を持っている2**23 -> 8388608
2つ(もちろん、あなたが、より多くの次の2のパワーを1カウントしなければならない意味の『包括的』部分)の隣接する大国の間で異なる値を。 double
sには52ビットの小数があります。
double
同等のものを書いて、「ねえ、私は約5分で自分の質問に答えます...」と思いました
double
、隣接する2の累乗の間で数えるのに約52日かかります(println
もちろん、どんなに高速に実行される可能性は非常に低いので、 1つのステートメントがなくなると仮定しましょう;-)。パワフルだが現実的なマシンで1年かそれ以下を取るのは現実的だと思う;-)。
詳細については、ウィキペディアの記事を参照してください。
1
隠されたビットは常に1であるため、間違っていると思います-したがって、明確な値で2^52
はありません (隣接する2の累乗の間、1つは含まれ、次の1は除外されます-0.0と1.0の間ではありません!)。2^53
Javaのdoubleは、IEEE 754のbinary64数です。
つまり、次のことを考慮する必要があります。
これは基本的に、2 ^ 62-2 ^ 52 + 1の合計があり、規格に従って0と1の間である可能性がある二重表現であることを意味します。2^ 52 + 1は、正規化されていないケースを削除することに注意してください番号。
仮数が正であるが指数が負である場合、数値は正であるが1未満であることに注意してください。
他の数値の場合、IEEE 754表現ではエッジの整数が正確に表現できない可能性があるため、また、数値を表すために指数で使用される他のビットがあるため、少し難しいです。異なる値。