web-dev-qa-db-ja.com

Cの浮動小数点データ型の範囲?

私は浮動小数点の範囲について話しているCの本を読んでいます、著者は表を与えました:

Type     Smallest Positive Value  Largest value      Precision
====     =======================  =============      =========
float    1.17549 x 10^-38         3.40282 x 10^38    6 digits
double   2.22507 x 10^-308        1.79769 x 10^308   15 digits

最小の正の値と最大の値の列の数字がどこから来るのかわかりません。

33
ipkiss

これらの数値は、浮動小数点数の標準表現を定義する IEEE-754 標準に基づいています。リンクのウィキペディアの記事 説明 符号、仮数、指数に使用されるビット数を知ってこれらの範囲に到達する方法。

18
dasblinkenlight

32ビットの浮動小数点数には、23 + 1ビットの仮数と8ビットの指数(ただし、-126〜127が使用されます)があるため、表現できる最大数は次のとおりです。

(1 + 1 / 2 + ... 1 / (2 ^ 23)) * (2 ^ 127) = 
(2 ^ 23 + 2 ^ 23 + .... 1) * (2 ^ (127 - 23)) = 
(2 ^ 24 - 1) * (2 ^ 104) ~= 3.4e38
28
Andreas Brinck

Floatデータ型の値は、次のように割り当てられる数を表すために合計32ビットを持つことに由来します。

1ビット:符号ビット

8ビット:指数p

23ビット:仮数

指数はp + BIASとして格納され、BIASは127、仮数は23ビット、1と想定される24番目の隠れビットを持ちます。この隠れビットは仮数の最上位ビット(MSB)であり、指数は1になるように選択します。

つまり、表現できる最小の数値は01000000000000000000000000000000であり、1x2^-126 = 1.17549435E-38です。

最大値は011111111111111111111111111111111、仮数は2 *(1-1/65536)、指数は127であり、(1 - 1 / 65536) * 2 ^ 128 = 3.40277175E38になります。

ビットが以下の場合を除き、同じ原則が倍精度に適用されます。

1ビット:符号ビット

11ビット:指数ビット

52ビット:仮数ビット

バイアス:1023

技術的には、制限は浮動小数点数を表現するためのIEEE-754標準に由来し、上記はこれらの制限がどのように発生するかです

7
SirGuy

Dasblinkenlightがすでに答えたように、数値は浮動小数点数がIEEE-754で表される方法に由来し、アンドレアスは数学のニースの内訳を持っています。

ただし、浮動小数点数の精度は、表が示すように正確に6桁または15桁の有効な10進数ではないことに注意してください。IEEE-754数値の精度は有効な2進数の数に依存するためです。

  • floatには24桁の有効な2進数があります。これは、表示される数値に応じて、精度が6〜8桁の10進数に変換されます。

  • doubleには53桁の有効な2進数があり、これは約15桁の10進数です。

私の別の答え 興味があるなら、さらなる説明があります。

2
Timothy Jones

無限大、NaN、非正規数

これらは重要な警告であり、他の回答ではこれまで言及していません。

最初に、IEEE 754と非正規数の紹介をお読みください。 非正規浮動小数点数とは?

次に、単精度浮動小数点数(32ビット)の場合:

  • IEEE 754は、指数がすべて1(0xFF == 255)の場合、NaNまたはInfinityを表すと述べています。

    これが最大の非無限数に指数0xFE == 254があり、0xFFではない理由です。

    次に、バイアスを使用すると、次のようになります。

    254 - 127 == 127
    
  • FLT_MINは、最小normal数です。しかし、より小さな非正規のものがあります!それらは-127指数スロットを使用します。

次のプログラムのすべてのアサートは、Ubuntu 18.04 AMD64で渡されます。

#include <assert.h>
#include <float.h>
#include <inttypes.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>

float float_from_bytes(
    uint32_t sign,
    uint32_t exponent,
    uint32_t fraction
) {
    uint32_t bytes;
    bytes = 0;
    bytes |= sign;
    bytes <<= 8;
    bytes |= exponent;
    bytes <<= 23;
    bytes |= fraction;
    return *(float*)&bytes;
}

int main(void) {
    /* All 1 exponent and non-0 fraction means NaN.
     * There are of course many possible representations,
     * and some have special semantics such as signalling vs not.
     */
    assert(isnan(float_from_bytes(0, 0xFF, 1)));
    assert(isnan(NAN));
    printf("nan                  = %e\n", NAN);

    /* All 1 exponent and 0 fraction means infinity. */
    assert(INFINITY == float_from_bytes(0, 0xFF, 0));
    assert(isinf(INFINITY));
    printf("infinity             = %e\n", INFINITY);

    /* ANSI C defines FLT_MAX as the largest non-infinite number. */
    assert(FLT_MAX == 0x1.FFFFFEp127f);
    /* Not 0xFF because that is infinite. */
    assert(FLT_MAX == float_from_bytes(0, 0xFE, 0x7FFFFF));
    assert(!isinf(FLT_MAX));
    assert(FLT_MAX < INFINITY);
    printf("largest non infinite = %e\n", FLT_MAX);

    /* ANSI C defines FLT_MIN as the smallest non-subnormal number. */
    assert(FLT_MIN == 0x1.0p-126f);
    assert(FLT_MIN == float_from_bytes(0, 1, 0));
    assert(isnormal(FLT_MIN));
    printf("smallest normal      = %e\n", FLT_MIN);

    /* The smallest non-zero subnormal number. */
    float smallest_subnormal = float_from_bytes(0, 0, 1);
    assert(smallest_subnormal == 0x0.000002p-126f);
    assert(0.0f < smallest_subnormal);
    assert(!isnormal(smallest_subnormal));
    printf("smallest subnormal   = %e\n", smallest_subnormal);

    return EXIT_SUCCESS;
}

GitHubアップストリーム

コンパイルして実行:

gcc -ggdb3 -O0 -std=c11 -Wall -Wextra -Wpedantic -Werror -o subnormal.out subnormal.c
./subnormal.out

出力:

nan                  = nan
infinity             = inf
largest non infinite = 3.402823e+38
smallest normal      = 1.175494e-38
smallest subnormal   = 1.401298e-45

これは、たとえばIEEE 754のように、型の指数部のサイズの結果です。 float.hのFLT_MAX、FLT_MIN、DBL_MAX、DBL_MINでサイズを調べることができます。

1
foo