Приведение беззнакового int к float

У меня есть 32-битное беззнаковое значение, которое я хочу преобразовать в ieee 754 с плавающей точкой.

Вот мои переменные:

unsigned int val = 0x3f800000;  
float floatVal;

Я знаю, что мне нужно сделать следующее, чтобы иметь возможность правильно преобразовать значение uint в значение с плавающей запятой ieee 754, которое я ожидаю от 1.0.

floatVal = *((float*)&val);

Может ли кто-нибудь объяснить, почему floatVal = (float) val не возвращает тот же результат? Вместо 1.0 floatVal получает значение 1.0653532e + 009. Я считаю, что это частично связано с тем, что биты теряются во время этого типа приведения типов, тогда как биты сохраняются посредством приведения указателей, но было бы очень полезно более подробное объяснение.

есть также порядок байтов. он возвращает 1.0, когда int 32-битный на машине с прямым порядком байтов. только что протестировал здесь. но вы должны использовать memcpy, чтобы избежать нарушения строгого правила псевдонима. вы должны использовать stdint & test endianness перед попыткой преобразования.

Jean-François Fabre 23.03.2018 23:10

Вкратце: float и unsigned представляют значения по-разному. Зависит от того, чего вы пытаетесь достичь. Чтобы преобразовать значение (например, чтобы 2U, преобразованный в float, имел значение 2.0f), используйте (float)val. Чтобы получить число с плавающей запятой, которое имеет такое же двоичное представление (но почти наверняка другое значение), используйте *((float *)&val) (имейте в виду, что последнее ПРЕДПОЛАГАЕТ, что float и unsigned имеют одинаковый размер и не будут работать, как вы описываете, для реализаций, использующих плавающие элементы, отличные от IEEE точка).

Peter 23.03.2018 23:16

приведение (float) val просто игнорирует тот факт, что val закодировано в формате IEEE и, следовательно, должно быть неправильным

Werner 24.03.2018 00:07

Чтобы объяснить, почему «получает значение 1.0653532e + 009», следует опубликовать код, ввести присвоение и распечатать его. А минимальный воспроизводимый пример

chux - Reinstate Monica 24.03.2018 01:02
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
5 563
1

Ответы 1

  1. В текущих стандартах C (C99, C11) следует каламбур через объединение, а не разыменование указателя с приведением типа:

    #include <stdint.h>
    
    uint32_t  float_bits(const float  f)
    {
        union {
            uint32_t  u;
            float     f;
        } temp;
    
        temp.f = f;
        return temp.u;
    }
    
  2. Большинство современных архитектур используют формат IEEE-754 двоичный32 для типа float, но не все. Если ваша программа предполагает это, это должно быть указано в документации.
    Я лично люблю проверять это во время компиляции и терпеть неудачу при компиляции, если мой код не справляется.

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

  4. В языке C выражение (type)variable преобразует значение переменной variable в тип type. Например:

    int32_t my_truncate(float value)
    {
        return (int32_t)value;
    }
    

    Если например value == 2.125, то my_truncate(value) == 2.

    Аналогично, приведение целочисленного значения к типу с плавающей запятой оценивается как значение с плавающей запятой, которое наилучшим образом представляет исходное целочисленное значение. Например, (float)425 == 425.0f. (Последний f просто сообщает, что значение относится к типу float. Если в конце значения с плавающей запятой нет f, его тип в C - double.)

  5. «Представление хранилища» относится к тому, как значения фактически хранятся в памяти.

  6. Разница между Кастинг и набирать текст заключается в том, что Кастинг переинтерпретирует само значение, а набирать текст переинтерпретирует то, как интерпретируется представление значения в хранилище.

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

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

  7. В C99 и более поздних версиях стандарта C, а также в реализациях POSIXy C вы можете использовать функцию frexpf() для разделения float на нормализованную дробь: Икс × 2n, где либо -1.0 <Икс <= -0.5f, либо 0.5 <= Икс <1; и n - целая экспонента.
    При необходимости можно использовать это для построения представления ближайшего значения, которое может представлять двоичный 32, в uint32_t. Это может быть полезно на архитектурах, которые не используют двоичный код IEEE 75432 для float.

Я только что многому научился. Спасибо за информативный пост.

Michael Dorgan 23.03.2018 23:35

Отличное объяснение. Спасибо!

Rolf 10.04.2019 18:27

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