Несколько вопросов о числах с плавающей запятой - PullRequest
1 голос
/ 06 октября 2010

Мне интересно, если число представляется одним способом в представлении с плавающей запятой, будет ли оно представлено таким же образом в представлении, которое имеет больший размер. То есть, если число имеет конкретное представление в виде float, будет ли оно иметь такое же представление, если это float приведено к double, а затем остается таким же, когда приведено к long double.

Мне интересно, потому что я пишу реализацию BigInteger и любое переданное число с плавающей запятой отправляю в функцию, которая принимает long double для ее преобразования. Что приводит меня к моему следующему вопросу. Очевидно, что плавающие точки не всегда имеют точные представления, поэтому в моем классе BigInteger, что я должен пытаться представить, когда дано число с плавающей точкой. Разумно ли пытаться представлять то же число, которое дано std::cout << std::fixed << someFloat;, даже если оно не совпадает с переданным числом. Это самое точное представление, которое я смогу получить? Если так, то ...

Каков наилучший способ извлечь это значение (в базовой степени 10), на данный момент я просто беру его как строку и передаю его моему строковому конструктору. Это сработает, но я не могу помочь, но чувствую, что есть лучший способ, но, конечно, брать остаток при делении на мою базу не совсем точно с поплавками.

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

Спасибо, Т.

Ответы [ 3 ]

9 голосов
/ 06 октября 2010

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

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

Преобразование через представление base-10 не является подходящим способом.Теоретически все, что вам нужно, это битовый массив длиной ~ 1024, инициализируйте все это до нуля, а затем сдвиньте биты мантиссы на величину экспоненты.Но, не зная больше о вашей реализации, я не могу предложить больше ничего!

2 голосов
/ 06 октября 2010

double включает все значения float;long double включает все значения double.Таким образом, вы не теряете никакой информации о стоимости при конвертации в long double.Однако вы теряете информацию об исходном типе, которая имеет отношение к делу (см. Ниже).

Чтобы следовать распространенной семантике C ++, преобразование значения с плавающей запятой в целое должно обрезать значение, а не округлять.

Основная проблема связана с большими значениями, которые не являются точными.Вы можете использовать функцию frexp, чтобы найти показатель степени 2 для значения с плавающей запятой.Вы можете использовать std::numeric_limits<T>::digits, чтобы проверить, находится ли он в целочисленном диапазоне, который может быть точно представлен.

Мой личный выбор дизайна будет утверждать, что значение fp находится в пределах диапазона, который может быть точно представлен, то естьограничение диапазона любого фактического аргумента.

Чтобы сделать это правильно, вам нужны перегрузки, принимающие аргументы float и double, поскольку диапазон, который может быть представлен, точно зависит от типа фактического аргумента.

Если у вас есть значение fp, которое находится в допустимом диапазоне, вы можете использовать floor и fmod для извлечения цифр в любой системе счисления, которую вы хотите.

0 голосов
/ 08 октября 2010

да, переходя от поплавка IEEE к удвоению до расширенного, вы увидите биты от меньшего формата к большему формату, например

single
S EEEEEEEE MMMMMMM.....
double 
S EEEEEEEEEEEE MMMMM....

6.5 single
0 10000001 101000...
6.5 double
0 10000000001 101000...
13 single
0 10000010 101000...
13 double
0 10000000010 101000...

Мантисса, которую вы оставите выравнивать, а затем добавьте нули.*

Показатель степени выровнен по правому краю, знак расширяется до msbit, затем копируется msbit.

Показатель степени -2, например.взять -2 вычесть 1, что составляет -3.-3 в дополнении к двум - 0xFD или 0b11111101, но биты экспоненты в формате равны 0b01111101, мсбит инвертирован.И для двойного показателя -2 -2 -2 = -3.или 0b1111 ... 1101, и это становится 0b0111 ... 1101, мсбит инвертируется.(биты экспоненты = twos_complement (экспонента-1) с инвертированным мсбитом).

Как мы видим выше, показатель степени 3 3-1 = 2 0b000 ... 010 инвертирует старший бит 0b100 ... 010

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

...