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