Как вывести целое число формата IEEE-754 как число с плавающей запятой

StackOverflow https://stackoverflow.com/questions/1856468

  •  13-09-2019
  •  | 
  •  

Вопрос

У меня есть длинное целое число без знака, которое представляет собой число с плавающей запятой в формате IEEE-754.Каков самый быстрый способ распечатать его как число с плавающей запятой на C++?

Я знаю один способ, но мне интересно, есть ли на C++ удобная утилита, которая была бы лучше.

Пример того, что я знаю:

union
{
    unsigned long ul;
    float f;
} u;

u.ul = 1084227584; // in HEX, this is 0x40A00000

cout << "float value is: " << u.f << endl;

(Это выводит «плавающее значение:5 дюймов)

Это было полезно?

Решение

Предложенный вами метод объединения — это обычный путь, по которому пойдет большинство людей.Однако технически это неопределенное поведение в C/C++ для чтения члена объединения, отличного от того, который был записан последним.Несмотря на это, он хорошо поддерживается практически всеми компиляторами.

Приведение указателей, как Джон Скит предложил, это плохая идея – это нарушает строгий псевдоним правила С.Агрессивный оптимизирующий компилятор выдаст при этом неверный код, поскольку предполагает, что указатели типов unsigned long * и float * никогда не будут псевдонимами друг друга.

Самый правильный способ, с точки зрения соответствия стандартам (то есть не вызывая неопределенного поведения), — это пропустить char*, поскольку строгие правила псевдонимов допускают char* указатель на псевдоним указателя любого другого типа:

unsigned long ul = 0x40A00000;
float f;
char *pul = (char *)&ul;  // ok, char* can alias any type
char *pf = (char *)&f;    // ok, char* can alias any type
memcpy(pf, pul, sizeof(float));

Хотя, честно говоря, я бы просто выбрал метод объединения.По ссылке на cell Performance.com выше:

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

Другие советы

Он будет работать только на 32-битных машинах или машинах, где sizeof(long) == sizeof(float).На современных машинах вместо этого вы можете использовать int...и вам действительно нужно быть осторожным, если вы выполняете этот трюк.

Я думал о том же, что и Джон Скит, но он меня опередил.Однако я бы сделал это немного более лаконично, чем он.

cout << "float value is: " << *((float *) &ulValue)) << endl;

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

Поскольку вы делаете это на C++, проще использовать reinterpret_cast вместо старого приведения в стиле C.

cout << "float value is: " << *(reinterpret_cast<float *>(&ulValue)) << endl;

РЕДАКТИРОВАТЬ:Раньше я думал, что это «просто противно», но оказалось, что это хуже, чем я думал — подробности смотрите в комментариях.Я бы не рекомендовал этот подход, но оставляю его здесь, чтобы документировать возможность (и предостережение!)


Вы можете использовать указатели:

long ul = 1084227584;
float* fp = (float*) &ul;
float f = *fp;

(Это можно сжать в одну строку, но я думаю, что проще этого не делать.)

По сути то же самое, что и ваш профсоюз...и столь же хитроумно, если вы не уверены в размерах задействованных типов.

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

Свеги указал правильное направление, но пропустил один символ.Правильный путь

long l = 1084227584L
float f = reinterpret_cast<float&>(l);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top