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


93

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

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

だから質問は:

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

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

回答:


68

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

doubles0.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

明確なdoubles-これは7036874417766.4004... 1つまたは2つを与えるか取る;-)。


@アレックス:ただ注意してください、100から100.1を書いたとき、私は間違って書いた。私は、任意のNのNとN + 1との間に、基本的に101に100を意味
polygenelubricants

4
@アレックス:ですから、これをまっすぐにしましょう:2**64可能なdouble値は(64ビット型であるため)あり得ず、それらの値の非常に大きな比率は0..1どうですか?
polygenelubricants

9
@polygene、yes and yes-具体的には、可能な値の約4分の1(ベースと指数と小数部の長さの「通常の」浮動小数点表現の場合)は0.0と1.0の間(1.0と無限大の間の別の四半期)、および実軸の負の半分に残りの半分)。基本的に、指数の値の半分(通常のバイアス、その範囲内の半分)は、ベースの負の累乗を表すため、数値<1.0です。
Alex Martelli

8
@polygenelubricants:多くのアプリケーションでは、0から1までの範囲が100から101までの範囲よりもはるかに重要で興味深いため、値のシェアが大きくなります。たとえば、物理学では、しばしば6.67e-11のニュートンの重力定数のように途方もなく小さい値を処理する必要があります。精度が高いと、100から101までよりも便利です。詳細については、floating-point-gui.deを参照してください。
Michael Borgwardt

1
0.0から1.0までの任意の数値をスケーリングして、スケールを個別に追跡し、計算のエラーを減らすこともできます。番号行全体を2つの番号間でマッピングできると便利です。
codekaizen

42

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

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

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

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

99999999999999982163600188718701095...

そして

10000000000000000159028911097599180...

+1、十分にサポートされている正確な回答。(エンドポイントのカウントにこだわりがある場合は、+ 0.0と-0.0の表現が異なることに注意してください。)
Jim Lewis

1
+1、こんなツイストエンディング!M.ナイトシャマランの脚本を読んでいるように感じました。
polygenelubricants 2010年

7

[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は生成されません。


3

記事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 - floatsが、その端数の23ビット分に相当を持っている2**23 -> 83886082つ(もちろん、あなたが、より多くの次の2のパワーを1カウントしなければならない意味の『包括的』部分)の隣接する大国の間で異なる値を。 doublesには52ビットの小数があります。
Alex Martelli

1
@アレックス:結果を得る前に、プログラム(ダブルス用に変更された)を宇宙の終わりまで実行したままにする必要があると思います... :(
Mark Rushakoff

1
私は馬鹿げていると感じます。私はdouble同等のものを書いて、「ねえ、私は約5分で自分の質問に答えます...」と思いました
多相潤滑剤

1
@polygene:これは、明らかなアプローチでは計算が実行できないプロジェクトオイラー問題のように感じられますが、任意のケースを解決するための見事に単純な式が必要です...
Mark Rushakoff

2
たぶん真にスーパーチャージされたスーパーコンピューターではないかもしれません:内側のループを実行するのにナノ秒しかかからないマシンではdouble、隣接する2の累乗の間で数えるのに約52日かかります(printlnもちろん、どんなに高速に実行される可能性は非常に低いので、 1つのステートメントがなくなると仮定しましょう;-)。パワフルだが現実的なマシンで1年かそれ以下を取るのは現実的だと思う;-)。
Alex Martelli

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

詳細については、ウィキペディアの記事参照してください。


2に対するあなたの答えは、私がFPの働きを理解する方法と矛盾しています。
polygenelubricants 2010年

1隠されたビットは常に1であるため、間違っていると思います-したがって、明確な値で2^52はありません (隣接する2の累乗の間、1つは含まれ、次の1は除外されます-0.0と1.0の間ではありません!)。2^53
Alex Martelli、

1

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

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

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

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

仮数が正であるが指数が負である場合、数値は正であるが1未満であることに注意してください。

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.