Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/139.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 这是什么;“非规范数据”;关于C++;_C++_Floating Point_Hardware_Cpu - Fatal编程技术网

C++ 这是什么;“非规范数据”;关于C++;

C++ 这是什么;“非规范数据”;关于C++;,c++,floating-point,hardware,cpu,C++,Floating Point,Hardware,Cpu,我想对“非规范数据”和它的内容有一个广泛的看法,因为我认为我唯一正确的是,从程序员的角度来看,它特别与浮点值有关,从CPU的角度来看,它与一般计算方法有关 有人能帮我解密这两个字吗 编辑 请记住,我是面向C++应用程序的,而C++语言是从 如果指数都是0,但分数不是零(否则会是零) 被解释为零),则该值为非规范化数字, 在二进制点之前没有假定的前导1。 因此,这表示一个数字(-1)s×0.f×2-126,其中s是 符号位和f是分数。对于双精度,非规范化 数字的形式为(-1)s×0.f×2-102

我想对“非规范数据”和它的内容有一个广泛的看法,因为我认为我唯一正确的是,从程序员的角度来看,它特别与浮点值有关,从CPU的角度来看,它与一般计算方法有关

有人能帮我解密这两个字吗

编辑

请记住,我是面向C++应用程序的,而C++语言是从

如果指数都是0,但分数不是零(否则会是零) 被解释为零),则该值为非规范化数字, 在二进制点之前没有假定的前导1。 因此,这表示一个数字(-1)s×0.f×2-126,其中s是 符号位和f是分数。对于双精度,非规范化 数字的形式为(-1)s×0.f×2-1022。从这里你可以 将零解释为一种特殊类型的非规范化数


您询问C++,但浮点值和编码的细节由浮点规范确定,特别是IEEE 754,而不是C++。IEEE 754是迄今为止使用最广泛的浮点规范,我将用它来回答

在IEEE 754中,二进制浮点值由三部分编码:符号位s(0表示正,1表示负)、偏置指数e(表示的指数加上固定偏移量)和有效位字段f(分数部分)。对于普通数字,它们正好表示数字(-1)s•2e bias•1.f,其中1.f是通过在“1”之后写入有效位而形成的二进制数字。(例如,如果有效位字段具有十位001011011,则它表示有效位1.00101101112,即1.182617175或1211/1024。)

偏差取决于浮点格式。对于64位IEEE 754二进制文件,指数字段有11位,偏差为1023。当实际指数为0时,编码指数字段为1023。-2、-1、0、1和2的实际指数具有1021、1022、1023、1024和1025的编码指数。当有人说一个次正常数的指数为零时,他们的意思是编码的指数为零。实际指数将小于-1022。对于64位,正常指数间隔为-1022到1023(编码值1到2046)。当指数超出这个区间时,会发生特殊的事情

超过此间隔,浮点停止表示有限数。2047的编码指数(全部1位)表示无穷大(有效位字段设置为零)。低于此范围时,浮点将更改为低于正常值的数字。当编码指数为零时,有效位字段表示0.f而不是1.f

这其中有一个重要原因。如果最低的指数值只是另一种正常编码,则其有效位的低位太小,无法单独表示为浮点值。如果没有前导的“1”,就无法说出第一个1位在哪里。例如,假设您有两个数字,都是指数最低的,有效位为1.00101101112和1.00000000002。减去有效位后,结果为.00101110112。不幸的是,没有办法将其表示为正常数字。因为您已经处于最低指数,所以您无法表示表示该结果中第一个1的位置所需的较低指数。由于数学结果太小而无法表示,计算机将被迫返回最接近的可表示数字,即零

这会在浮点系统中创建不需要的属性,您可以使用
a!=b
a-b==0
。为了避免这种情况,使用了低于正常值的数字。通过使用次正常数,我们有一个特殊的区间,实际指数不会减少,并且我们可以执行算术,而不会创建太小而无法表示的数字。当编码指数为0时,实际指数与编码指数为1时相同,但有效位的值更改为0.f而不是1.f。当我们这样做时,
a!=b
保证
a-b
的计算值不为零

以下是64位IEEE 754二进制浮点编码中的值组合:

Sign Exponent (e) Significand Bits (f) Meaning 0 0 0 +zero 0 0 Non-zero +2-1022•0.f (subnormal) 0 1 to 2046 Anything +2e-1023•1.f (normal) 0 2047 0 +infinity 0 2047 Non-zero but high bit off +, signaling NaN 0 2047 High bit on +, quiet NaN 1 0 0 -zero 1 0 Non-zero -2-1022•0.f (subnormal) 1 1 to 2046 Anything -2e-1023•1.f (normal) 1 2047 0 -infinity 1 2047 Non-zero but high bit off -, signaling NaN 1 2047 High bit on -, quiet NaN 符号指数(e)有效位(f)含义 0+0 0 0非零+2-1022•0.f(低于正常值) 0 1至2046任意值+2e-1023•1.f(正常值) 0 2047 0+无穷大 0 2047非零但高位关闭+,信号为NaN 0 2047高位on+,安静NaN 100-0 10非零-2-1022•0.f(低于正常值) 1至2046年任何时间-2e-1023•1.f(正常) 120470-无限 1 2047非零但高位关闭-信号NaN 1 2047高位on-,安静NaN 一些注意事项:

+0和-0在数学上相等,但符号保留。精心编写的应用程序可以在某些特殊情况下使用它

NaN的意思是“不是一个数字”。通常,这意味着发生了一些非数学结果或其他错误,应放弃或以另一种方式重新进行计算。通常,使用NaN的操作会生成另一个NaN,从而保留出错的信息。例如,
3+NaN
生成一个NaN。信号NaN旨在引起异常,以指示程序出错或允许其他软件(例如调试器)执行某些特殊操作。一个安静的NaN旨在传播到更多的res
  0 == special case: zero or subnormal, explained below
  1 == 2 ^ -126
    ...
125 == 2 ^ -2
126 == 2 ^ -1
127 == 2 ^  0
128 == 2 ^  1
129 == 2 ^  2
    ...
254 == 2 ^ 127
255 == special case: infinity and NaN
25.0   == (binary) 11001 == 1.1001 * 2^4
 0.625 == (binary) 0.101 == 1.01   * 2^-1
1.000002 * 2 ^ (-127)
1.0 * 2 ^ (-126)
0.FFFFFE * 2 ^ (-126)
0.000002 * 2 ^ (-126)
0.000002 * 2 ^ (-126)
0.000002 * 2 ^ (-126) / 2
#if __STDC_VERSION__ < 201112L
#error C11 required
#endif

#ifndef __STDC_IEC_559__
#error IEEE 754 not implemented
#endif

#include <assert.h>
#include <float.h> /* FLT_HAS_SUBNORM */
#include <inttypes.h>
#include <math.h> /* isnormal */
#include <stdlib.h>
#include <stdio.h>

#if FLT_HAS_SUBNORM != 1
#error float does not have subnormal numbers
#endif

typedef struct {
    uint32_t sign, exponent, fraction;
} Float32;

Float32 float32_from_float(float f) {
    uint32_t bytes;
    Float32 float32;
    bytes = *(uint32_t*)&f;
    float32.fraction = bytes & 0x007FFFFF;
    bytes >>= 23;
    float32.exponent = bytes & 0x000000FF;
    bytes >>= 8;
    float32.sign = bytes & 0x000000001;
    bytes >>= 1;
    return float32;
}

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 float32_equal(
    float f,
    uint32_t sign,
    uint32_t exponent,
    uint32_t fraction
) {
    Float32 float32;
    float32 = float32_from_float(f);
    return
        (float32.sign     == sign) &&
        (float32.exponent == exponent) &&
        (float32.fraction == fraction)
    ;
}

void float32_print(float f) {
    Float32 float32 = float32_from_float(f);
    printf(
        "%" PRIu32 " %" PRIu32 " %" PRIu32 "\n",
        float32.sign, float32.exponent, float32.fraction
    );
}

int main(void) {
    /* Basic examples. */
    assert(float32_equal(0.5f, 0, 126, 0));
    assert(float32_equal(1.0f, 0, 127, 0));
    assert(float32_equal(2.0f, 0, 128, 0));
    assert(isnormal(0.5f));
    assert(isnormal(1.0f));
    assert(isnormal(2.0f));

    /* Quick review of C hex floating point literals. */
    assert(0.5f == 0x1.0p-1f);
    assert(1.0f == 0x1.0p0f);
    assert(2.0f == 0x1.0p1f);

    /* Sign bit. */
    assert(float32_equal(-0.5f, 1, 126, 0));
    assert(float32_equal(-1.0f, 1, 127, 0));
    assert(float32_equal(-2.0f, 1, 128, 0));
    assert(isnormal(-0.5f));
    assert(isnormal(-1.0f));
    assert(isnormal(-2.0f));

    /* The special case of 0.0 and -0.0. */
    assert(float32_equal( 0.0f, 0, 0, 0));
    assert(float32_equal(-0.0f, 1, 0, 0));
    assert(!isnormal( 0.0f));
    assert(!isnormal(-0.0f));
    assert(0.0f == -0.0f);

    /* ANSI C defines FLT_MIN as the smallest non-subnormal number. */
    assert(FLT_MIN == 0x1.0p-126f);
    assert(float32_equal(FLT_MIN, 0, 1, 0));
    assert(isnormal(FLT_MIN));

    /* The largest subnormal number. */
    float largest_subnormal = float_from_bytes(0, 0, 0x7FFFFF);
    assert(largest_subnormal == 0x0.FFFFFEp-126f);
    assert(largest_subnormal < FLT_MIN);
    assert(!isnormal(largest_subnormal));

    /* 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));

    return EXIT_SUCCESS;
}
gcc -ggdb3 -O0 -std=c11 -Wall -Wextra -Wpedantic -Werror -o subnormal.out subnormal.c
./subnormal.out
          +---+-------+---------------+
exponent  |126|  127  |      128      |
          +---+-------+---------------+
          |   |       |               |
          v   v       v               v
          -----------------------------
floats    ***** * * * *   *   *   *   *
          -----------------------------
          ^   ^       ^               ^
          |   |       |               |
          0.5 1.0     2.0             4.0
          +---+---+-------+---------------+
exponent  | ? | 0 |   1   |       2       |
          +---+---+-------+---------------+
          |   |   |       |               |
          v   v   v       v               v
          ---------------------------------
floats    *   ***** * * * *   *   *   *   *
          ---------------------------------
          ^   ^   ^       ^               ^
          |   |   |       |               |
          0   |   2^-126  2^-125          2^-124
              |
              2^-127
          +-------+-------+---------------+
exponent  |   0   |   1   |       2       |
          +-------+-------+---------------+
          |       |       |               |
          v       v       v               v
          ---------------------------------
floats    * * * * * * * * *   *   *   *   *
          ---------------------------------
          ^   ^   ^       ^               ^
          |   |   |       |               |
          0   |   2^-126  2^-125          2^-124
              |
              2^-127