Преобразование числа с плавающей запятой в 16-битное двоичное значение в C

Это мой код. Когда я меняю мантиссу, показатель степени и знак на 23, 8 и 1 соответственно, чтобы представить 32-битное число, мой код работает. Однако когда значения изменяются для представления битового соотношения в соответствии с 16-битным форматом, он не возвращает правильное значение.

#include <stdio.h>
#include <stdlib.h>
typedef union
{
  float val;
  struct
  {
    unsigned int mantissa: 10;
    unsigned int exponent: 5;
    unsigned int sign: 1;
  }float16;
 
}IEEE_FP;

void print(unsigned int val, int num_bits)
{
  for(int i = num_bits-1; i >= 0; i--)
    {
      if ((val>>i)&1){printf("1");}
      else{printf("0");}
    }
}

void print16(IEEE_FP test)
{
  print(test.float16.sign, 1);
  print(test.float16.exponent, 5);
  print(test.float16.mantissa, 10);
}


int main()
{

  IEEE_FP test;
  test.val = 0.789;
  print16(test);
  return EXIT_SUCCESS;
}

Я пытался передать число с плавающей запятой 0,789 и ожидал 0011101001010000, однако мой код печатает 1111101111100111. Есть идеи?

Число с плавающей запятой — 32-битное число. Вы просто берете первые 16 битов в своем союзе. Если вам нужно сжатое представление, вам нужно иметь 13 неизвестных бит мантиссы и извлечь 8-битный компонент, выяснить, каково его значение в дополнении до 2, и представить его в 5 битах.

cup 28.07.2024 07:21

Извините, показатель степени также имеет формат знаковой мантиссы: не является дополнением до 2. бит мс 1=+ve, 0=-ve.

cup 28.07.2024 10:18

Ваш код print16 может подойти. Однако вам нужен лучший способ проверить это. Вам нужен способ передачи фактических 16-битных тестовых значений. Если ваш компилятор не поддерживает тип float16, лучше всего добавить uint16_t hexval к вашему объединению, а затем передать значения таким образом, например, test.hexval = 0x5044;.

Steve Summit 28.07.2024 12:40
0x5044 должен был дать вам 34.125. Другие тестовые примеры: 0x3c00 → 1.0; 0xc000 → -2,0; 0x3e00 → 1,5; 0x2e66 → 0,1 (приблизительно).
Steve Summit 30.07.2024 02:22
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
97
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Причина, по которой код работает для 32-битного значения float, заключается в том, что когда значение сохраняется в члене float val объединения, оно сохраняется с использованием представления для 32-битного типа float. (Этот тип представляет собой формат двоичного32 IEEE-754, также называемый IEEE-754 «одинарной точности».) Это представление создается с помощью комбинации аппаратного и программного обеспечения, анализирующего строку 0.789 в исходном коде и преобразующего ее в формат двоичный32.

Объединение работает, потому что битовые поля члена struct объединения используют тот же член, что и член float val объединения. Чтение значений с использованием битовых полей интерпретирует биты как целые числа, а не как двоичные32. Затем, имея эти значения в виде целых чисел, ваша программа может их распечатать. (Кроме того, расположение битовых полей во многом определяется реализацией. Стандарт C обеспечивает гибкость в порядке и выравнивании битовых полей относительно байтов в памяти. Поэтому этот код не является переносимым.)

Когда вы меняете определения битовых полей, чтобы они имели ширину для 16-битного типа с плавающей запятой, в float val ничего не меняется. Те же биты для двоичного файла32 все еще находятся в памяти. Ничто автоматически не изменяет биты в float val на биты 16-битного типа с плавающей запятой вместо битов двоичного типа32.

Чтобы отобразить биты, которые будут представлять значение в 16-битном типе с плавающей запятой, у вас обычно есть два варианта:

  • Замените float в float val на имя 16-битного типа с плавающей запятой. Это не указано в стандарте C, но ваш компилятор может иметь для этого тип.
  • Напишите программу для расчета того, какими будут биты. Для этого может потребоваться отделить знак числа, вычислить, какой показатель следует использовать, масштабировать мантиссу для ее нормализации и округлить биты мантиссы до 11 бит.

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

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