0
votes

There is a catch!

I have a IEEE 754 single precision (32 bit) float stored in two consecutive 16bit integers.

The processor I am using doesn't have floating point maths or float data types! What I want to do is convert the float value into a 16bit signed integer. The processor has standard integer maths and bit manipulation (masking, shifting etc).

I except that I will need to lose some precision in going from a 32bit float to a 16bit integer. The integer will also need some implied scaling factor based upon the value ranges in question.

Here's a simple example to make things clearer. Say the float has a range of 0.00 to 10.00. In this case I want the integer to range from 0 to 1000. Note the implied scaling factor of 100. In this case the integer has an implied scaling of 100.

I know that the IEEE 754 contains 1 sign bit, 8 bits for the exponent (with 127 bias) and 23 bits for the mantissa.

I know the equation to reconstruct the value from the float's constituent parts is:

float value = (-1)^Sign_bit * (1+Mantissa) * 2^(Exponent-127).

The main problem I can see is working with 16bit signed integers (range of -32768 to +32767) and avoiding any overflow or underflow.

1
I don't understand what you want answered. - Prof. Falken

1 Answers

0
votes

You want to convert 32 bit floats to 16 bit integers with scaling. However, the example you give uses a decimal scaling and not a binary. I'm unsure if you want to keep working in the binary domain on a system without a floating point unit or if you actually want to convert to decimal representation of the number.

Here I assume that your challenge is that you don't have access to floating point instructions. You haven't specified a programming language so I decided to code some stuff in C#. The language is easy to use but perhaps not the most suited for bit fiddling. You may find it easier and more efficient to implement this in say C or C++.

As I'm going to keep using a binary representation the scale cannot be a number like 10 or 100 (an integral power of 10) but instead has to be an integral power of 2. Below is a class to take an IEEE 754 binary32 floating point number apart.

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);
  }

}

The method ToScaledInt16 is what you want to use. If you want to express numbers using fractions of 8 you should supply the value 3 for scaling. All number will be multiplied by 2^3 = 8, e.g. 0.125 = 1/8 is converted to 1, 0.25 = 2/8 to 2 etc.

The code does not handle more complex stuff like rounding, NaN or overflow but perhaps you can use it as a starting point?