38

我正在读一本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

我不知道最小正值和最大值列中的数字来自哪里。

4

6 回答 6

31

一个 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
于 2012-04-11T14:42:26.600 回答
22

这些数字来自IEEE-754标准,该标准定义了浮点数的标准表示。链接中的维基百科文章解释了如何在知道用于符号、尾数和指数的位数的情况下达到这些范围。

于 2012-04-11T14:37:19.783 回答
8

浮点数据类型的值来自总共 32 位来表示分配的数量,如下所示:

1位:符号位

8 位:指数 p

23 位:尾数

指数存储为p + BIASBIAS 为 127,尾数有 23 位和第 24 个隐藏位,假设为 1。此隐藏位是尾数的最高有效位 (MSB),必须选择指数以便它是1.

这意味着您可以表示的最小数字010000000000000000000000000000001x2^-126 = 1.17549435E-38

最大值是011111111111111111111111111111111,尾数是 2 * (1 - 1/65536),指数是 127,给出(1 - 1 / 65536) * 2 ^ 128 = 3.40277175E38

相同的原则适用于双精度,除了位是:

1位:符号位

11位:指数位

52位:尾数位

偏差:1023

所以从技术上讲,限制来自表示浮点数的 IEEE-754 标准,以上是这些限制的产生方式

于 2012-04-11T15:04:42.850 回答
3

无穷大、NaN 和次正规

这些是迄今为止没有其他答案提到的重要警告。

首先阅读 IEEE 754 和次正规数的介绍:什么是次正规浮点数?

然后,对于单精度浮点数(32 位):

  • IEEE 754 规定,如果指数全为 ( 0xFF == 255),则它表示 NaN 或 Infinity。

    这就是为什么最大的非无限数有指数0xFE == 254而不是0xFF

    然后有了偏差,它变成:

    254 - 127 == 127
    
  • FLT_MIN是最小的正规数。但也有更小的不正常的!那些占据了-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
于 2018-11-08T09:10:11.723 回答
2

正如 dasblinkenlight 已经回答的那样,这些数字来自 IEEE-754 中浮点数的表示方式,Andreas 对数学进行了很好的分解。

但是 - 请注意,浮点数的精度并不完全是 6 或 15 位有效十进制数字,因为 IEEE-754 数字的精度取决于有效二进制数字的数量。

  • float有 24 位有效的二进制数字 - 根据所表示的数字转换为 6-8 位精度的十进制数字。

  • double有 53 个有效二进制数字,大约是 15 个十进制数字。

如果您有兴趣,我的另一个答案有进一步的解释。

于 2012-04-11T14:49:44.350 回答
1

这是类型的指数部分大小的结果,例如在 IEEE 754 中。您可以在 float.h 中使用 FLT_MAX、FLT_MIN、DBL_MAX、DBL_MIN 检查大小。

于 2012-04-11T14:40:39.283 回答