什么是浮点数的“偏差值”?
在学习如何在计算机中表示浮点数的过程中,我遇到了“偏差值”这个我不太明白的术语。
浮点数中的偏差值与浮点数的指数部分的负值和正值有关。
浮点数的偏移值是127,这意味着总是将127添加到浮点数的指数部分。 这样做如何帮助确定指数是否为负值或正值?
在单精度浮点数中,可以得到8位来存储指数。 不是把它作为一个带符号的二进制补码存储起来,而是决定只给指数加127(因为最低可能是8位有符号的是-127),并且把它存储为一个无符号数。 如果存储值大于偏差,则表示指数值为正值,如果低于偏差值,则为负值,如果相等则为零。
b0lt已经解释了偏见是如何工作的。 在猜测,也许你想知道为什么他们在这里使用偏见表示,即使几乎所有的现代计算机实际上在其他地方使用二进制补码(甚至机器不使用补码,使用补码或符号大小,而不是偏见)。
IEEE浮点标准的目标之一就是可以将浮点数的位作为一个具有相同大小的(带符号)整数,如果你用这种方式进行比较,这些值将按照与它们表示的浮点数。
如果对指数使用二进制补码表示,则小的正数(即负指数)看起来像一个非常大的整数,因为第二个MSB将被设置。 通过使用偏差表示来代替,您不会遇到这种情况 – 浮点数中较小的指数总是看起来像一个较小的整数。
FWIW,这也是为什么浮点数通常首先按照符号排列,然后是指数,最后是最低有效位的有效数 – 这样就可以取正数浮点数,把这些位作为整数,sorting他们。 当你这样做,结果将有正确的顺序浮点数。 例如:
#include <vector> #include <algorithm> #include <iostream> int main() { // some arbitrary floating point values std::vector<double> vals = { 1e21, 1, 2.2, 2, 123, 1.1, 0.0001, 3, 17 }; std::vector<long long> ivals; // Take those floating point values, and treat the bits as integers: for (auto &&v : vals) ivals.push_back(*reinterpret_cast<long long *>(&v)); // Sort them as integers: std::sort(ivals.begin(), ivals.end()); // Print out both the integers and the floating point value those bits represent: for (auto &&i : ivals) std::cout << i << "\t(" << *reinterpret_cast<double *>(&i) << ")\n"; }
当我们运行这个时,结果如下所示:
4547007122018943789 (0.0001) 4607182418800017408 (1) 4607632778762754458 (1.1) 4611686018427387904 (2) 4612136378390124954 (2.2) 4613937818241073152 (3) 4625478292286210048 (17) 4638355772470722560 (123) 4921056587992461136 (1e+21)
正如你所看到的那样,即使我们将它们sorting为整数,这些位表示的浮点数也按正确的顺序出现。
这对浮点数有一定的限制。 虽然所有的(非古代的)计算机都同意正数的表示forms,但是有三种表示forms(近来已经用于有符号数字):符号大小,补码和二进制补码。
只要将这些位作为一个整数来比较,就可以在使用整数有符号幅度表示的计算机上正常工作。 对于使用补码或二进制补码的计算机,负号将按相反顺序sorting。 由于这仍然是一个简单的规则,所以编写与之配合的代码是相当容易的。 如果我们将上面的sort
调用改为如下所示:
std::sort(ivals.begin(), ivals.end(), [](auto a, auto b) { if (a < 0.0 && b < 0.0) return b < a; return a < b; } );
…然后它将正确地sorting正面和负面的数字。 例如,input:
std::vector<double> vals = { 1e21, 1, 2.2, 2, 123, 1.1, 0.0001, 3, 17, -0.001, -0.00101, -1e22 };
会产生以下结果:
-4287162073302051438 (-1e+22) -4661071411077222194 (-0.00101) -4661117527937406468 (-0.001) 4547007122018943789 (0.0001) 4607182418800017408 (1) 4607632778762754458 (1.1) 4611686018427387904 (2) 4612136378390124954 (2.2) 4613937818241073152 (3) 4625478292286210048 (17) 4638355772470722560 (123) 4921056587992461136 (1e+21)
为上面的答案添加更多的细节。
为了表示infinity
为0
, infinity
和NaN
(非数字),IEEE决定使用特殊的编码值。
-
如果指数字段的所有位都设置为0,则浮点数为0.0。
-
如果指数字段的所有位都设置为1,小数部分的所有位都是0,那么浮点数是无穷大的 。
-
如果指数字段的所有位都设置为1,并且小数部分的所有位都不等于0,则浮点数是NaN 。
因此,单精度我们有8位来表示指数字段,并有2个特殊值,所以我们基本上有256 - 2 = 254
值,可以用指数表示。 因此,我们可以有效地表示指数中的-126到127,即254个值(126 + 127 + 1),1加上0。