什么是浮点数的"偏差值"?

mud*_*dge 48 floating-point

在学习如何在计算机中表示浮点数时,我遇到了"偏差值"一词,我不太明白.

浮点数中的偏差值与浮点数的指数部分的负和正有关.

浮点数的偏差值为127,这意味着127总是被添加到浮点数的指数部分.这样做有助于确定指数是否为负数或正数?

Jer*_*fin 66

b0lt已经解释了偏见是如何起作用的.猜测一下,也许你想知道为什么他们在这里使用偏差表示,尽管几乎所有的现代计算机都在其他地方使用两个补码(甚至机器不使用二进制补码,使用一个补码或符号量级,而不是偏见).

IEEE浮点标准的目标之一是您可以将浮点数的位视为相同大小的(带符号)整数,如果您按照这种方式对它们进行比较,则值的排序顺序与他们所代表的浮点数.

如果对指数使用二进制补码表示,则小的正数(即带有负指数)看起来像一个非常大的整数,因为第二个MSB将被设置.相反,通过使用偏差表示,您不会遇到这种情况 - 浮点数中的较小指数总是看起来像一个较小的整数.

FWIW,这也是为什么浮点数通常被安排与符号,再指数,终于在最显著位有效数字 - 这样一来,你可以采取积极的浮点数,把这些位为整数,排序他们.执行此操作时,结果将以正确的顺序具有浮点数.例如:

#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";
}
Run Code Online (Sandbox Code Playgroud)

当我们运行它时,结果如下所示:

4547007122018943789     (0.0001)
4607182418800017408     (1)
4607632778762754458     (1.1)
4611686018427387904     (2)
4612136378390124954     (2.2)
4613937818241073152     (3)
4625478292286210048     (17)
4638355772470722560     (123)
4921056587992461136     (1e+21)
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,即使我们将它们排序为整数,这些位表示的浮点数也会以正确的顺序出现.

这对浮点数有限制.虽然所有(非古代)计算机都同意正数的表示,但有三种表示(最近)用于有符号数:有符号量,一个补码和二进制补码.

只需将这些位视为整数并进行比较,就可以在使用整数的有符号幅度表示的计算机上正常工作.对于使用一个补码或两个补码的计算机,负数将按倒序排序.由于这仍然是一个简单的规则,因此编写适合它的代码非常容易.如果我们将sort上面的调用更改为以下内容:

std::sort(ivals.begin(), ivals.end(),
    [](auto a, auto b) { if (a < 0.0 && b < 0.0) return b < a; return a < b; }
);
Run Code Online (Sandbox Code Playgroud)

......然后它会正确地对正数和负数进行排序.例如,输入:

std::vector<double> vals = { 1e21, 1, 2.2, 2, 123, 1.1, 0.0001, 3, 17, -0.001, -0.00101, -1e22 };
Run Code Online (Sandbox Code Playgroud)

会产生以下结果:

-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)
Run Code Online (Sandbox Code Playgroud)

  • @JerryCoffin:+1一个很好的答案(特别是在fp数字组件中排序背后的基本原理). (3认同)
  • @ user1534664:我做了一些编辑(我希望)澄清最后一点. (2认同)

Jos*_*Gao 58

在单精度浮点中,您可以获得8位来存储指数.不是将它存储为带符号的二进制补码数,而是决定将指数添加127更容易(因为8位有符号的最低值是-127)并且只是将其存储为无符号数.如果存储的值大于偏差,则表示指数的值为正,如果它低于偏差,则为负,如果等于,则为零.

  • 为什么最低8位有符号数-127?不应该是-128吗?n 位有符号整数范围应为 -2^(n-1), 2^(n-1)-1 (5认同)
  • @JimmySuh,将指数位视为一些 8 位无符号整数会更直观:“255”为 Inf/NaN 保留,“254”映射到 127,...,“1”映射到 -126,“ 0` 保留为 0/denorms(可视化:https://www.h-schmidt.net/FloatConverter/IEEE754.html) (2认同)

小智 16

在上面的答案中添加更多细节.

来表示0,infinityNaN(不非数字)在浮点,IEEE决定使用特殊编码值.

  • 如果指数字段的所有位都设置为0,则浮点数为0.0.

  • 如果指数字段的所有位都设置为1并且小数部分的所有位都是0,则浮点数是无穷大.

  • 如果指数字段的所有位都设置为1并且小数部分的所有位都不等于0,则浮点数为NaN.

因此,在单精度中,我们有8位来表示指数字段,并且有2个特殊值,因此我们基本上具有256 - 2 = 254可以用指数表示的值.因此,我们可以在指数中有效地表示-126到127,即254个值(126 + 127 + 1),为0添加1.