2009-02-08 5 views
5

Возможно ли вычислить диапазоны типов данных с плавающей точкой, двойными и длинными двойными портами без чтения float.h и использования ANSI C? В переносном я имею в виду те случаи, когда целевая машина не придерживается стандарта IEEE 754.Вычисление диапазонов типов данных с плавающей точкой

Я читаю книгу R и упражнение 2-1 K & просит меня «вычислить» их таким образом я предполагаю, что означает, избегая float.h полностью, который включает в себя FLT_MIN, FLT_MAX, DBL_MIN и DBL_MAX (читать эти значения непосредственно будет конечно, не классифицируются как «вычисления»).

+0

Почему, по вашему мнению, это означает, что вы избегаете float.h? ну, я думаю, он хочет, чтобы вы использовали какую-то функцию вроде ldexp, FLT_RADIX (или как ее называли) и т. д. –

+0

Хорошо, потому что float.h уже имеет доступные значения min/max, которые в этом случае выглядят как обман. Но да, есть некоторые другие константы, определенные в float.h, которые, вероятно, могут быть использованы для определения реальных диапазонов. – Ree

ответ

3

На риск избыточного ответа:

No. Существует не переносимый способ для вычисления диапазонов. Вот почему заголовок <float.h> предоставляется - потому что нет портативного способа получения информации, содержащейся в нем.

+2

Это правда - но есть расчеты, которые будут работать для широкого спектра схем кодирования! – Christoph

2

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

+0

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

+0

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

4

За 99,99% всех приложений вы должны принять IEEE 754 и использовать константы, определенные в <float.h>. В других 0,01% вы будете работать с очень специализированным оборудованием, и в этом случае вы должны знать, что использовать на основе аппаратного обеспечения.

11

Это возможно (по крайней мере, для IEEE 754 float и double значений) вычислить наибольшее значение с плавающей запятой с помощью (псевдо-код):

~(-1.0) | 0.5 

Прежде чем мы сможем сделать наш битовую вертел, мы» Мне нужно преобразовать значения с плавающей запятой в целые числа, а затем снова вернуться. Это можно сделать следующим образом:

uint64_t m_one, half; 
double max; 

*(double *)(void *)&m_one = -1.0; 
*(double *)(void *)&half = 0.5; 
*(uint64_t *)(void *)&max = ~m_one | half; 

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

Самый старший бит кодирует знак, следующий бит k кодирует показатель экспоненты, а младшие разряды будут содержать дробную часть. Для полномочий 2 дробная часть равна 0.

Показатель будет сохранен с смещением (смещением) 2**(k-1) - 1, что означает, что показатель 0 соответствует шаблону со всеми, но с самым высоким битом.

Есть два показателя битовые модели с особым значением:

  • если не бит не установлен, то значение будет 0, если дробная часть равна нулю; в противном случае значение является субнормальная
  • , если все биты установлены, то значение либо infinity или NaN

Это означает, что наибольший регулярный показатель будет закодирован с помощью установки всех битов, кроме самого нижнего, что соответствует значение 2**k - 2 или 2**(k-1) - 1, если вы вычтите смещение.

Для double значения, k = 11, т.е. самый высокий показатель будет 1023, поэтому наибольшее значение с плавающей запятой порядка 2**1023 который составляет около 1E+308.

Наибольшее значение будет иметь

  • знаковый бит установлен в 0
  • всех, но самый низкий показатель бит установлен в 1
  • все дробные биты, установленные в 1

Теперь, можно понять, как работают наши магические числа:

  • -1.0 имеет свой знак установлен бит, показатель степени смещения - то есть все биты, но самый высокий в настоящее время - и дробная часть 0
  • ~(-1.0) имеет только самый высокий показатель степени бит и все дробные биты устанавливают
  • 0.5 имеет знаковый бит и дробную часть 0; показатель будет смещение минус 1, то есть все, но высокий и самый низкий показатель степени бит будет присутствовать

Когда мы объединяем эти два значения через логическое или, мы получим битовую комбинацию мы хотели.


Вычисление работает для x86 80-битной расширенных значений точности (ака long double), а также, но немного-вертел должен быть сделан побайтно, как нет целого типа достаточно велик, чтобы вместить значения на 32- бит.

Уклонение на самом деле не должно быть 2**(k-1) - 1 - он будет работать для произвольного уклона, если он нечетный. Смещение должно быть нечетным, поскольку в противном случае битовые шаблоны для показателя 1.0 и 0.5 будут отличаться в других местах, чем младший бит.

Если база b (ака радикс) типа с плавающей точкой не 2, вы должны использовать b**(-1) вместо 0.5 = 2**(-1).

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


Резюмируя:

~(-1.0) | 0.5 

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

~(-1.0) | 1.0 

работает для любого радиуса или смещения, пока не указан самый высокий показатель экспоненты.

+0

Высказывание «для IEEE 754» отрицает предпосылку вопроса. –

+1

@ Джонатан: «по крайней мере для» не было означать «только для» - это работает для каждого значения с плавающей запятой с уклоном «2 ** (k-1) - 1' и зарезервированным показателем« 2 » ** k - 1', который включает в себя значения половины и четверной точности, а также 80-битные расширенные значения точности на x86 – Christoph

+1

@ Джонатан: Как еще вы хотите «вычислить» что-то, если вы не ограничите возможные схемы кодирования? Там просто нет алгоритма, который будет работать для всех кодировок! – Christoph

Смежные вопросы