8

I was looking for a way to convert IEEE floating point numbers to IBM floating point format for a old system we are using.

Is there a general formula we can use in C# to this end?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
aiw
  • 129
  • 1
  • 2
  • 7

4 Answers4

9

Use:

// https://en.wikipedia.org/wiki/IBM_hexadecimal_floating-point
//
// float2ibm(-118.625F) == 0xC276A000
// 1 100 0010    0111 0110 1010 0000 0000 0000
//
// IBM/370 single precision, 4 bytes
// xxxx.xxxx     xxxx.xxxx xxxx.xxxx xxxx.xxxx
// s|-exp--|     |--------fraction-----------|
//    (7)                   (24)
//
// value = (-1)**s * 16**(e - 64) * .f   range = 5E-79 ... 7E+75
//
static int float2ibm(float fromFormat)
{
    byte[] bytes = BitConverter.GetBytes(fromFormat);
    int fconv = (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8)| bytes[0];

    if (fconv == 0)
        return 0;
    int fmant = (0x007fffff & fconv) | 0x00800000;
    int t = (int)((0x7f800000 & fconv) >> 23) - 126;
    while (0 != (t & 0x3)) {
        ++t;
        fmant >>= 1;
    }
    fconv = (int)(0x80000000 & fconv) | (((t >> 2) + 64) << 24) | fmant;
    return fconv; // Big-endian order
}

I changed a piece of code called static void float_to_ibm(int from[], int to[], int n, int endian).

The code above can be run correctly on a PC.

from is a little-endian float number. return value is a big-endian IBM float number, but stored in type int.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
speeding
  • 133
  • 1
  • 6
  • This really saved my life, I wish I could reward you 50 reputation points to both of you speeding and Noam M, I just don't find how. A notice: in my case I had to read the bytes of the returned int in reverse order to get the printable output to windows-1252 encoded file (little endian). It was for SAS XPORT. – barbara.post Aug 24 '17 at 07:58
  • 1
    I'd love it if I could understand this well enough to expand it to 64-bit doubles. Which document is this implementation sourced from? – Travis Parks Mar 07 '19 at 04:10
  • IEEE-754 `float` supports -0: I _think_ this value isn't treated correctly. Changing the first check to become `((fconv & 0x7fffffff) == 0)` should fix that problem. As the IBM floating point format does support negative 0, too, the sign bit could be added back but it doesn't seem negative 0 is maintained with IBM floating point arithmetic. – Dietmar Kühl Dec 03 '19 at 23:59
2

An obvious approach would be to use textual representation of the number as the interchange format.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
0

I recently had to convert one float to another. It looks like the XDR format uses an odd format for its floats. So when converting from XDR to standard floats, this code did it.

#include <rpc/rpc.h>

// Read in an XDR float array, copy to a standard float array.
// The 'out' array needs to be allocated before the function call.

bool convertFromXdrFloatArray(float *in, float *out, long size)
{
    XDR xdrs;
    xdrmem_create(&xdrs, (char *)in, size*sizeof(float), XDR_DECODE);

    for(int i = 0; i < size; i++)
    {
        if(!xdr_float(&xdrs, out++)) {
            fprintf(stderr, "%s:%d:ERROR:xdr_float\n", __FILE__, __LINE__);
            exit(1);
        }
    }
    xdr_destroy(&xdrs);

    return true;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
phyatt
  • 18,472
  • 5
  • 61
  • 80
0

Using speeding's answer, I added the following that may be useful in some cases:

/// <summary>

/// Converts an IEEE floating number to its string representation (4 or 8 ASCII codes).
/// It is useful for SAS XPORT files format.
/// </summary>
/// <param name="from_">IEEE number</param>
/// <param name="padTo8_">When true, the output is 8 characters rather than 4</param>
/// <returns>Printable string according to the hardware's endianness</returns>
public static string Float2IbmAsAsciiCodes(float from_, bool padTo8_ = true)
{
    StringBuilder sb = new StringBuilder();
    string s;
    byte[] bytes = BitConverter.GetBytes(Float2Ibm(from_)); // Big-endian order

    if (BitConverter.IsLittleEndian)
    {
        // Revert bytes order
        for (int i = 3; i > -1; i--)
            sb.Append(Convert.ToChar(bytes[i]));
        s = sb.ToString();
        if (padTo8_)
            s = s.PadRight(8, '\0');
        return s;
    }
    else
    {
        for (int i = 0; i < 8; i++)
            sb.Append(Convert.ToChar(bytes[i]));
        s = sb.ToString();
        if (padTo8_)
            s = s.PadRight(8, '\0');
        return s;
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
barbara.post
  • 1,581
  • 16
  • 27