web-dev-qa-db-ja.com

0.0と1.0の間にある倍数はいくつありますか?

これは何年も頭に浮かんだことですが、前に尋ねる時間はありませんでした。

多くの(疑似)乱数ジェネレーターが0.0から1.0までの乱数を生成します。数学的には、この範囲には無限の数がありますが、doubleは浮動小数点数であるため、精度は有限です。

だから質問は:

  1. 0.0と1.0の間にあるdoubleの数はいくつですか?
  2. 1と2の間の数だけありますか? 100から101の間? 10 ^ 100と10 ^ 100 + 1の間?

注:違いがある場合、特にJavaのdoubleの定義に興味があります。

92

Java doublesは IEEE-754 形式であるため、52ビットの小数になります。したがって、2つの隣接する2の累乗(1を含み、次の1を除く)の間には、2の52乗のdoublesがあります(つまり、4503599627370496)。たとえば、これは、0.5が含まれていて1.0が除外されている間のdoublesの数であり、その多くは、1.0が含まれているから2.0が除外されているなどのことも同様です。

0.0から1.0の間のdoublesを数えることは、2のべき乗の間で行うよりも、2のべき乗がその範囲に含まれるため、非正規化数の厄介な問題に遭遇するため、困難です。指数の11ビットのうち10ビットが問題の範囲をカバーしているため、非正規化数(およびNaNのいくつかの種類を含む)を含めると、間にdoublesが1024倍あるはずです2の累乗-とにかく合計で2**62以下。非正規化された&cを除くと、カウントは2**52の1023倍になると思います。

「100から100.1」のような任意の範囲では、上限をdoubleとして正確に表すことができないため、さらに困難です(2のべき乗の正確な倍数ではありません)。便利な近似として、2の累乗間の進行は線形であるため、その範囲は2の累乗(64と128)の間のスパンの0.1 / 64thであると言えます。

(0.1 / 64) * 2**52

明確なdoubles-これは7036874417766.4004...になります。

67
Alex Martelli

表現が0x00000000000000000x3ff0000000000000の間にあるすべてのdouble値は、間隔[0.0、1.0]にあります。これは(2 ^ 62-2 ^ 52)の異なる値です(エンドポイントをカウントするかどうかに応じて、プラスまたはマイナスのカップル)。

間隔[1.0、2.0]は、0x3ff00000000000000x400000000000000の間の表現に対応します。それは2 ^ 52の異なる値です。

間隔[100.0、101.0]は、0x40590000000000000x4059400000000000の間の表現に対応します。それは2 ^ 46の異なる値です。

10 ^ 100と10 ^ 100 + 1の間にはダブルはありません。これらの数値のどちらも倍精度で表現できず、それらの間にある倍精度はありません。最も近い2つの倍精度数は次のとおりです。

99999999999999982163600188718701095...

そして

10000000000000000159028911097599180...
41
Stephen Canon

[0.0、1.0]の範囲に約2 ^ 62の倍数があることをすでに説明している人もいます。
(本当に驚くべきことではありません:ほぼ2 ^ 64の異なる有限の倍精度数があります。そのうちの半分は正であり、約の半分 1.0未満です。)

しかし、乱数ジェネレータについて言及します。0.0と1.0の間の数を生成する乱数ジェネレータは、一般にこれらすべての数を生成できないことに注意してください。通常、n/2整数のn/2 ^ 53の形式の数値のみが生成されます(たとえば、Javaのドキュメント nextDouble を参照)。したがって、通常は約2 ^ 53(含まれるエンドポイントに応じて+/- 1)random()出力の可能な値これは、[0.0、1.0]のほとんどのdoubleが生成されないことを意味します。

7
Mark Dickinson

IBMの記事 Javaの新しい数学、パート2:浮動小数点数 は、これを解決する次のコードスニペットを提供しています(浮動小数点数ですが、倍精度浮動小数点数でも機能すると思います):

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と呼ばれます。

3
Mark Rushakoff
  1. 2 ^ 53-隠しビットを含む64ビット浮動小数点数の仮数/仮数のサイズ。
  2. Sifnificandは固定されていますが、指数は変化するので、大体はい。

詳細は wikipediaの記事 を参照してください。

2
Yann Ramin

Java doubleはIEEE 754 binary64の数値です。

つまり、次のことを考慮する必要があります。

  1. 仮数は52ビットです
  2. 指数は、1023バイアスの11ビット数です(つまり、1023が追加されています)。
  3. 指数がすべて0で仮数がゼロ以外の場合、数値は正規化されていないと言われます

これは基本的に、標準に従って0と1の間の合計2 ^ 62-2 ^ 52 + 1の可能な二重表現があることを意味します。2^ 52 + 1は非正規化のケースを削除することに注意してください番号。

仮数が正で指数が負の場合、数値は正ですが1未満です:-)

他の数値の場合、IEEE 754表現ではEdge整数が正確に表現できない可能性があるため、また、数値を表すことができるように指数で使用される他のビットがあるため、少し難しいです。異なる値。

1
njsf