Что такое “значение предвзятости” чисел с плавающей запятой?

В изучении, как числа с плавающей точкой представлены в компьютерах, я столкнулся с термином "предвзятость значения", которую я действительно не совсем понимаю.

Значение предвзятости в числах с плавающей точкой имеет отношение к отрицанию и положительности части экспоненты числа с плавающей точкой.

Значение предвзятости числа с плавающей точкой равняется 127, что означает, что 127 всегда добавляется к части экспоненты числа с плавающей точкой. Как делает выполнение этой справки, определяют, отрицательна ли экспонента или положительна или нет?

47
задан nbro 19 March 2016 в 01:42
поделиться

2 ответа

В числах с плавающей запятой одинарной точности вы получаете 8 бит для хранения показателя степени. Вместо того, чтобы хранить его как число дополнения до двух со знаком, было решено, что было бы проще просто добавить 127 к экспоненте (так как наименьшее значение может быть в 8-битном подписанном - -127) и просто сохранить его как беззнаковое число. . Если сохраненное значение больше смещения, это означает, что значение экспоненты положительное, если оно ниже смещения, оно отрицательное, если равно, то ноль.

57
ответ дан 7 November 2019 в 12:57
поделиться

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";
}

Когда мы выполняем это, результат выглядит так:

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

Как вы можете видеть, несмотря на то, что мы отсортировали их как целые числа, числа с плавающей запятой, которые представляют эти биты, также выходят в правильном порядке.

Это имеет ограничения в отношении чисел с плавающей запятой. Хотя все (не древние) компьютеры согласны с представлением положительных чисел, есть три представления, которые (сравнительно недавно) использовались для знаковых чисел: знаковая величина, дополнение единицы и дополнение двойки.

Простое обращение с битами как с целым числом и сравнение будет хорошо работать на компьютере, который использует представление знаковой величины для целых чисел. На компьютерах, использующих представление с дополнением один или два, отрицательные числа будут сортироваться в инвертированном порядке. Поскольку это простое правило, довольно легко написать код, который работает с ним. Если мы изменим приведенный выше вызов sort на что-то вроде этого:

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

... то он будет правильно сортировать как положительные, так и отрицательные числа. Например, ввод:

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)
66
ответ дан 7 November 2019 в 12:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: