Эвристика, чтобы определить, является ли серия 4-байтовых блоков данных целыми числами или плаваниями

Что лучшей является эвристика, которую я могу использовать, чтобы определить, является ли блок X 4 байтов целыми числами или плаваниями? Человек может сделать это легко, но я хотел сделать это программно.

Я понимаю, что начиная с каждой комбинации битов приведет к допустимому целому числу и (почти?) все они также приведут к допустимому плаванию, нет никакого способа знать наверняка. Но я все еще хотел бы идентифицировать наиболее вероятного кандидата (который фактически всегда будет корректен; или по крайней мере, человек может сделать это).

Например, давайте возьмем серию 4-байтовых необработанных данных и распечатаем их как целые числа сначала и затем как плавания:

1           1.4013e-45
10          1.4013e-44
44          6.16571e-44
5000        7.00649e-42
1024        1.43493e-42
0           0
0           0
-5          -nan
11          1.54143e-44

Очевидно, они будут целыми числами.

Теперь, другой пример:

1065353216  1
1084227584  5
1085276160  5.5
1068149391  1.33333
1083179008  4.5
1120403456  100
0           0
-1110651699 -0.1
1195593728  50000

Они, очевидно, будут плаваниями.

PS: я использую C++, но можно ответить на любом языке, псевдо коде или только на английском языке.

11
задан flint 21 March 2010 в 00:53
поделиться

9 ответов

Вы собираетесь смотреть на верхние 8 или 9 бит. Вот где находятся знак и мантисса значения с плавающей запятой. Значения 0x00 0x80 и 0xFF здесь довольно необычны для действительных данных с плавающей запятой.

В частности, если все верхние 9 битов равны 0, то это, вероятно, будет действительным значением с плавающей запятой только в том случае, если все 32 бита равны 0. Другой способ сказать это: если показатель степени равен 0, мантисса также должна быть равна нулю. . Если верхний бит равен 1, а следующие 8 бит - 0, это допустимо, но также маловероятно. Он представляет -0.0, что является допустимым значением с плавающей запятой, но бессмысленным.

Чтобы выразить это в числовом выражении. если старший байт равен 0x00 (или 0x80), то значение имеет величину максимум 2.35e-38. Постоянная Планка составляет 6,62e-34 м2 кг / с, что на 4 порядка больше. Предполагаемый диаметр протона намного больше (оценивается в 1,6e − 15 метров). Наименьшее ненулевое значение для аудиоданных составляет около 2,3e-10. Вы вряд ли увидите, что значения с плавающей запятой являются законными измерениями чего-либо реального, меньшего, чем 2.35e-38, но не нуля.

В другом направлении, если старший байт равен 0xFF, то это значение либо Infinite, либо NaN, либо больше по величине, чем 3,4e + 38. Возраст Вселенной оценивается в 1,3e + 10 лет (1,3e + 25 фемтосекунд). Наблюдаемая Вселенная имеет примерно e + 23 звезд, число Авагадро - 6.02e + 23.И снова значения с плавающей запятой больше, чем e + 38, редко появляются в достоверных измерениях.

Это не означает, что FPU не может загружать или выдавать такие значения, и вы обязательно увидите их в промежуточных значениях вычислений, если вы работаете с современными FPU. Современный FPU загружает значение с плавающей запятой, у которого показатель степени равен 0, но другие биты не равны 0. Они называются денормализованными значениями. Вот почему вы видите небольшие положительные целые числа, которые отображаются как значения с плавающей запятой в диапазоне e-42, хотя нормальный диапазон значений с плавающей запятой только опускается до e-38

Показатель всех единиц представляет бесконечность. Вы, вероятно, не найдете бесконечностей в своих данных, но вы бы знали лучше, чем я. -Infinity - это 0xFF800000, + Infinity - это 0x7F800000, любое значение, кроме 0 в мантиссе Infinity, искажено. уродливые бесконечности используются как NaN.

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

0
ответ дан 3 December 2019 в 07:37
поделиться

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

Кроме того, очевидно, что если значение является неправильным с плавающей запятой, оно является целым числом: -)

Кажется достаточно прямым для реализации.

4
ответ дан 3 December 2019 в 07:37
поделиться

Вы, вероятно, сможете «обнаружить» это, посмотрев на старшие биты, с плавающей точкой они обычно не равны нулю, с целыми числами, если вы не имеете дело с очень большим числом. Итак ... вы можете попробовать и посмотреть, возвращает ли (2 ^ 30) & number 0 или нет.

1
ответ дан 3 December 2019 в 07:37
поделиться

Человек может сделать это легко

Человек вообще не может этого сделать. Ergo не может и компьютер. Имеется 2 ^ 32 допустимых значений типа int. Многие из них также являются допустимыми значениями с плавающей запятой. Нет другого способа отличить цель данных, кроме как пометить их или вообще не попасть в такой беспорядок.

Не пытайтесь это сделать.

1
ответ дан 3 December 2019 в 07:37
поделиться

Если вы знаете, что все ваши числа с плавающей запятой будут фактическими значениями (без NaN, INF, денормальных значений или других отклоняющихся значений), вы можете использовать этот критерий. Как правило, массив целых чисел с высокой вероятностью содержит «плохие» значения с плавающей запятой.

0
ответ дан 3 December 2019 в 07:37
поделиться

Если оба числа положительны, ваши числа с плавающей запятой достаточно большие ( больше 10 ^ -42), а ваши целые числа достаточно малы (меньше 8 * 10 ^ 6), то проверка довольно проста. Рассматривайте данные как число с плавающей запятой и сравнивайте с наименее нормализованным числом с плавающей запятой.

union float_or_int {
    float f;
    int32_t i;
};

bool is_positive_normalized_float( float_or_int &u ) {
    return u.f >= numeric_limits<float>::min();
}

Предполагается, что IEEE float и одинаковая конечная скорость между CPU и FPU.

1
ответ дан 3 December 2019 в 07:37
поделиться

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

9
ответ дан 3 December 2019 в 07:37
поделиться

Упрощая то, что сказал Алан, я бы посмотрел ТОЛЬКО на целочисленную форму. и скажем, если число больше 99999999, то это почти наверняка число с плавающей запятой.

Это имеет то преимущество, что это быстро, легко и позволяет избежать проблем с нанотехнологиями.

У него есть недостаток в том, что он в значительной степени полон дерьма ... Я на самом деле не смотрел, какие поплавки они будут представлять или что-то в этом роде, но из ваших примеров это выглядит разумным ...

В любом случае, это это эвристика, так что ГОННА будет полная чушь, да и не всегда срабатывает ...

Измерьте микрометром, отметьте мелом, отрежьте топором.

0
ответ дан 3 December 2019 в 07:37
поделиться

Я предполагаю следующее:

  • вы имеете в виду числа с плавающей запятой одинарной точности IEEE 754.
  • что знаковый бит числа с плавающей запятой сохраняется в старшем разряде int.

Итак, начнем:

static boolean probablyFloat(uint32_t bits) {
  bool sign = (bits & 0x80000000U) != 0;
  int exp = ((bits & 0x7f800000U) >> 23) - 127;
  uint32_t mant = bits & 0x007fffff;

  // +- 0.0
  if (exp == -127 && mant == 0)
    return true;

  // +- 1 billionth to 1 billion
  if (-30 <= exp && exp <= 30)
    return true;

  // some value with only a few binary digits
  if ((mant & 0x0000ffff) == 0)
    return true;

  return false;
}

int main() {
  assert(probablyFloat(1065353216));
  assert(probablyFloat(1084227584));
  assert(probablyFloat(1085276160));
  assert(probablyFloat(1068149391));
  assert(probablyFloat(1083179008));
  assert(probablyFloat(1120403456));
  assert(probablyFloat(0));
  assert(probablyFloat(-1110651699));
  assert(probablyFloat(1195593728));
  return 0;
}
0
ответ дан 3 December 2019 в 07:37
поделиться
Другие вопросы по тегам:

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