Подтвердить что ты не робот

Что такое "значение смещения" чисел с плавающей запятой?

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

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

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

4b9b3361

Ответ 1

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

Ответ 2

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)

Ответ 3

Добавление более подробной информации к приведенным выше ответам.

Чтобы представить 0, infinity и NaN (Not-a-Number) в плавающей точке, IEEE решил использовать специальные значения кодировки.

  • Если все биты поля экспоненты установлены в 0, то число с плавающей запятой равно 0.0.

  • Если все биты поля экспоненты установлены равными 1, а все биты части дроби равны 0, то число с плавающей запятой равно бесконечности.

  • Если все биты поля экспоненты установлены в 1, и все биты части дроби не равны 0, то число с плавающей запятой равно NaN.

Итак, в единственной точности мы имеем 8 бит для представления поля экспоненты, и есть 2 специальных значения, поэтому мы имеем в основном значения 256 - 2 = 254, которые могут быть представлены в экспоненте. Таким образом, мы можем эффективно представлять от -126 до 127 в экспоненте, то есть 254 значения (126 + 127 + 1), 1 добавляется для 0.

Ответ 4

Чтобы конкретно устранить вашу путаницу: показатель степени может казаться отрицательным из-за предвзятости. Если вы видите двоичное значение +125 в диапазоне экспоненты, после того, как вы его "распределили", фактическое значение экспоненты будет -2. Это может произойти, потому что быть "предвзятым" в этом контексте означает вычитать 127. Есть время, когда показатель степени останется положительным даже после вычитания 127. Если вы просто смотрите на биты:

[0][01111111][00000000000000000000000] - это ноль! Даже если вы видите все эти 1 здесь. Эти примеры предназначены для чисел с плавающей запятой одинарной точности (32 бита) для процессоров, использующих стандарт IEEE 754. При использовании этого стандартного значения сохраняются так:

[sign][biased exponent][significand] Бит SIGN используется для дробной части числа с плавающей запятой, а НЕ для показателя степени. Ваши глаза должны переместить знаковый бит и показатель степени, чтобы эти числа выглядели более естественными, скажем 1.01x2 ^ 5, как вы видели бы в классе математики. Кстати, 1.01x2 ^ 5 считается "нормальным" числом, потому что слева от двоичной точки есть только 1 цифра, и, конечно, эта версия научной записи умножается на 2, а не на 10, потому что мы используем базу 2, что делает перемещение бинарной точки легко!

Давайте посмотрим на пример, подобный десятичному 0,15625, сначала я визуально переместлю показатель степени:


----------------------------------(exponent) 0 01111100 01000000000000000000000 ^ --+------+-+----------------------- | | | | +------+ | subtract 127 here | | | v | ---------------->--------------
Here the exponent is 124, so subtract 127 to get -3. Now remember the implied 1 so you'll now have 1.01000000000000000000000. Forget all those zeros: 1.01x2^-3 is the binary number 0.001010. Also remember, the first bit was a zero so the "finalized" number is a positive 0.15625. We could easily have -0.15625 if we had 1 01111100 01000000000000000000000 to start with.

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

                       
     31                               
     |                                
     | 30    23 22                    0
     | |      | |                     |
-----+-+------+-+---------------------+
qnan 0 11111111 10000000000000000000000
snan 0 11111111 01000000000000000000000
 inf 0 11111111 00000000000000000000000
-inf 1 11111111 00000000000000000000000
-----+-+------+-+---------------------+
     | |      | |                     |
     | +------+ +---------------------+
     |    |               |
     |    v               v
     | exponent        fraction
     |
     v
     sign

Я нашел все это в Руководстве Intel, Таблица 4-3 на стр. 91 в наборе 4 об.