pythonturbo-pascal

Convert a Python float value to Turbo Pascal's 48‑bit real in Python


I am trying to convert a floating number to 48‑bit Real (from Borland Pascal) in Python. I have found this method written in C# (I think):

static byte[] DoubleToReal48(double d)
{
  byte[] r = new byte[6];

  long bits = BitConverter.DoubleToInt64Bits(d);
  bool negative = ((bits >> 63) & 1) != 0;
  long exponent = ((bits >> 52) & 0x7FF) - 1023;
  long mantissa = bits & 0xFFFFFFFFFFFFFL;

  long raw = (negative ? 1 : 0);
  raw = (raw << 39) | (mantissa >> 13);
  raw = (raw << 8) | ((exponent + 129) & 0xFF);

  for (int k = 0; k < 6; k++)
  {
    r[k] = (byte)(raw & 0xFF);
    raw >>= 8;
  }
  return r;
}

I don’t know C#, so I’m having a hard time translating it to Python. Can anyone help me? Or perhaps there is a better way?

I have found this but it seems to only convert 48‑bit Real to double, not the other way around as I need.


Solution

  • Let me try to translate the C# to python

    1.- Convert the bits from a double number to a number (unsigned long long).

    long bits = BitConverter.DoubleToInt64Bits(d);
    

    translates to

    struct.unpack("Q", struct.pack("d", python_double) )[0]
    

    it uses the struct module from standard library.

    2.- Extract each field from the double representation

    bool negative = ((bits >> 63) & 1) != 0;
    long exponent = ((bits >> 52) & 0x7FF) - 1023;
    long mantissa = bits & 0xFFFFFFFFFFFFFL;
    

    That can translated alsmot verbatim, since the same operators exist in python.

    negative = ((bits >> 63) & 1)    # Integer 1 for negative, 0 for positive
    exponent = ((bits >> 52) & 0x7FF) - 1023
    mantissa = bits & 0xFFFFFFFFFFFFF
    

    3.- Pack again the number into 48 bits

    long raw = (negative ? 1 : 0);
    raw = (raw << 39) | (mantissa >> 13);
    raw = (raw << 8) | ((exponent + 129) & 0xFF);
    

    Same as number 2,

    raw = negative
    raw = (raw << 39) | (mantissa >> 13)
    raw = (raw << 8) | ((exponent + 129) & 0xFF)
    

    4.- Convert the number to a string of 6 bytes

    for (int k = 0; k < 6; k++)
    {
      r[k] = (byte)(raw & 0xFF);
      raw >>= 8;
    }    
    

    Use struct as in step 1,

    data = struct.pack('Q', raw)
    data = data[:6]  # Drop the 16 MSB
    

    NOTE: I'm dropping the last 2 chars because struct uses the processors' endianness by default (x86 in my case), but that can be controlled with the first argument.

    TIP: If you want to convert a number to a binary representation you could use '{:064b}'.format(number). This will pad it with zeros to fill 64 chars.