Преобразование числа с плавающей точкой в ​​целое число - PullRequest
0 голосов
/ 22 февраля 2012

Есть подвох!

У меня есть IEEE 754 с плавающей запятой одинарной точности (32 бита), хранящиеся в двух последовательных 16-битных целых числах.

Процессор, который я использую, не имеет математических операций с плавающей запятой или типов данных с плавающей запятой! Что я хочу сделать, это преобразовать значение с плавающей точкой в ​​16-битное целое число со знаком. Процессор имеет стандартные целочисленные математические и битовые манипуляции (маскирование, сдвиг и т. Д.).

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

Вот простой пример, чтобы прояснить ситуацию. Скажем, у поплавка есть диапазон от 0.00 до 10.00. В этом случае я хочу, чтобы целое число варьировалось от 0 to 1000. Обратите внимание, что подразумеваемый коэффициент масштабирования равен 100. В этом случае целое число имеет предполагаемый коэффициент масштабирования, равный 100.

Я знаю, что IEEE 754 содержит 1 знаковый бит, 8 бит для показателя степени (с 127 смещением) и 23 бита для мантиссы.

Я знаю, что уравнение для восстановления значения из составных частей поплавка:

значение с плавающей запятой = (-1) ^ знак_бит * (1 + мантисса) * 2 ^ (экспонента-127).

Основная проблема, которую я вижу, это работа с 16-битными целыми числами со знаком (диапазон от -32768 до +32767) и предотвращение любого переполнения или недополнения.

1 Ответ

0 голосов
/ 22 февраля 2012

Вы хотите преобразовать 32-битные числа с плавающей точкой в ​​16-битные целые числа с масштабированием.Однако в приведенном вами примере используется десятичное масштабирование, а не двоичное.Я не уверен, хотите ли вы продолжать работать в двоичном домене в системе без единицы с плавающей запятой или если вы действительно хотите преобразовать в десятичное представление числа.

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

Поскольку я собираюсь продолжать использовать двоичное представление, шкала не может быть числом, подобным 10 или 100 (целая степень 10) но вместо этого он должен иметь целочисленную степень 2. Ниже приведен класс, который разбирает число двоичных чисел IEEE 754 с двоичным числом 32.

class Ieee754Binary32 {

  public Ieee754Binary32(Single value) {
    using (var memoryStream = new MemoryStream()) {
      var binaryWriter = new BinaryWriter(memoryStream);
      binaryWriter.Write(value);
      memoryStream.Seek(0, SeekOrigin.Begin);
      var binaryReader = new BinaryReader(memoryStream);
      var bits = binaryReader.ReadInt32();
      Fraction = bits & 0x7FFFFF;
      Exponent = ((bits >> 23) & 0xFF) - 127;
      Sign = (bits & 80000000) == 1 ? -1 : 1;
    }
  }

  public Int32 Fraction { get; private set; }

  public Int32 Exponent { get; private set; }

  public Int32 Sign { get; private set; }

  public Int16 ToScaledInt16(Int32 scaling) {
    if (Exponent == -127 && Fraction == 0)
      return 0;
    var mantissa = 0x8000 | (Fraction >> 8);
    var unscaledInt32 = Exponent >= 0 ? mantissa << Exponent : mantissa >> -Exponent;
    var scaledInt16 = unscaledInt32 >> (15 - scaling);
    return (Int16) (Sign*scaledInt16);
  }

}

Метод ToScaledInt16 - это то, что вы хотите использовать.Если вы хотите выразить числа, используя дроби 8, вы должны указать значение 3 для scaling.Все числа будут умножены на 2^3 = 8, например, 0,125 = 1/8 преобразуется в 1, 0,25 = 2/8 в 2 и т. Д.

Код не обрабатывает более сложные вещи, такие как округление, NaN или переполнениено, возможно, вы можете использовать его в качестве отправной точки?

...