Я пытаюсь понять статью о сжатии без потерь чисел с плавающей запятой и застрял на одном конкретном этапе, где авторы отображают целое число со знаком из определенного диапазона в диапазон, равный половине размера, потеря информации, которую я считаю необходимой. У меня такое ощущение, что авторы используют какую-то стандартную технику, которая настолько очевидна для их аудитории, что они не пытаются объяснить, но которая совершенно непрозрачна для меня.
Свернутое значение - это разница между двумя 23-разрядными положительными целыми числами (мантиссами предсказанного и фактического значения с плавающей запятой), которая находится между 1 - 2 23 и 2 * 1007. * 23 - 1. Авторы перемещают числа с наивысшими значениями (отрицательными и положительными) «внутрь», поэтому результирующий диапазон равен половине размера, и каждое число (кроме 0) отображается на два возможных значения из исходного диапазона , Это заставляет меня задуматься о том, как процесс должен быть полностью изменен, чтобы определить первоначальное значение. По словам авторов:
Мы вычисляем подписанный корректор, который является самым коротким по модулю 2 23 и числом k
, которое задает самый короткий интервал (1-2 k , 2 k ) в который попадает этот корректор. Затем это число k
, которое находится в диапазоне от 0 до 22, сжимается [...]. Наконец, k + 1
значащие биты корректора сжимаются.
Псевдокод для этого задается как:
void comp mantissa(int expo, int a, int p) {
// c will be within [1-2^23 ... 2^23 -1]
int c = a - p;
// wrap c into [1-2^22 ... 2^22 ]
if (c <= -(1<<22)) c += 1<<23;
else if (c > (1<<22)) c -= 1<<23;
// find tightest [1-2^k ... 2^k ] containing c
int k = 0;
// loop could be replaced with faster code
int c1 = (c < 0 ? -c : c);
while (c1) { c1 = c1 >> 1; k++ }
// adjust k for case that c is exactly 2k
if (k && (c == 1<<(k-1))) k--;
// .. further code omitted for brevity
}
Игнорируя фактический метод сжатия, вывод состоит из c
и k
. Что я не получаю, это: Как я могу восстановить исходные c
из c
и k
, когда вышеприведенная часть "wrap c into" просто отображает половину потенциального диапазона на другую половину? Я попробовал это на бумаге с 4 вместо 23 бит, и я просто не понимаю.