Help defining a custom IBMFloat32 primitive type

If you want to keep the bit-level approach (as opposed to doing a final computation in Float64), then you either use leading_zeros or modify your loop. You also need to adjust the biases. The function now looks similar the previous bit-level code:

function juliohm2(b::UInt32)
    s = b & 0x80000000
    e = b & 0x7f000000
    f = b & 0x00ffffff

    # if fraction is zero, value is zero
    iszero(f) && return zero(Float64)

    # shift sign bit to the rightmost position
    sieee = Int64(s >> 31)

    # shift exponent bits to the right (3 bytes = 24 bits)
    # and multiply by 4 to convert from base 16 to base 2
    # hence, the resulting shift is 24 - 2 = 22 bits
    eieee = Int64(e >> 22)
    eieee += 1023 - 4*64 # adjust bias

    # normalize fraction until the leading digit is equal to 1,
    # and adjust the exponent accordingly (opposite shift)
    while iszero(f & 0x00800000)
        f <<= 1
        eieee -= 1
    end
    f = (f << 1) & 0x00ffffff # drop leading bit
    eieee -= 1 # account for dropped leading bit
    fieee = UInt64(f) << (52 - 24) # pad with zeros to the right

    reinterpret(Float64, sieee << 63 | eieee << 52 | fieee)
end
1 Like

Thank you @matthias314 , I am learning a lot about these bit manipulations from your code snippets. I will try to simplify the code further based on the last version you shared.

@matthias314 regarding this line, shouldn’t it just be 1023 - 64? Where is the 4 coming from?

My understanding from your previous comments:

  # exponent of 64 means 0 in the IBM standard, and
  # exponent of 1023 means 0 in the IEEE standard
  # hence, the bias adjustment is -64 + 1023 = 959
  eieee += 959

Regarding this line, could you please elaborate on how you arrived at (52 - 24)?

The IBM floats exponents are to base 16 and the IEEE floats exponents to base 2.

1 Like

The fraction is 24 bits for IBM and 52 bits for IEEE floats.

I would like to suggest again that you look at some examples from the Wikipedia page and see what the various steps of the code mean for them.

1 Like

I am finally grasping these shifts…

The 32-bit IBM floating point has the following layout:

The 64-bit IEEE floating point has the following layout:

Here is an updated implementation:

function Base.convert(::Type{Float64}, x::IBMFloat32)
  # extract sign, exponent, and fraction bits
  b = reinterpret(UInt32, x)
  s = b & 0x80000000
  e = b & 0x7f000000
  f = b & 0x00ffffff

  # if fraction is zero, value is zero
  iszero(f) && return zero(Float64)

  # position sign bit at the leftmost bit of 8 bytes
  sieee = Int64(s) << 32

  # shift exponent bits to the right (3 bytes = 24 bits)
  # and multiply by 4 to convert from base 16 to base 2
  # hence, the resulting shift is 24 - 2 = 22 bits
  eieee = Int64(e >> 22)

  # exponent of 64 in base 16 means 0 in the IBM standard,
  # and exponent of 1023 in base 2 means 0 in the IEEE standard
  # hence, the bias adjustment is 1023 - 4*64 = 767
  eieee += 767

  # shift fraction bits to the left until the leading digit is 1
  # and then drop the leading 1 as it is implicit in IEEE
  shift = leading_zeros(f) - 8 # ignore sign and exponent bits
  fieee = UInt64((f << (shift + 1)) & 0x00ffffff)
  eieee -= (shift + 1)

  # pad fraction with zeros to the right, and since IEEE
  # uses 52 bits for the fraction and IBM uses 24 bits,
  # we need to shift 52 - 24 = 28 bits to the left
  fieee <<= 28

  # now that the exponent bits have been adjusted, shift
  # them to their final position in the IEEE representation
  eieee <<= 52

  # reinterpret bits as Float64
  reinterpret(Float64, sieee | eieee | fieee)
end
2 Likes

Which? The conversion is here (to Float32, not sure you get NaN for out of range, it’s huge you likely don’t need to support all of it):

also supporting that format in case it’s what you needed… I believe there are very few, maybe only also some FDA format needing hexadecimal.

The standard also allows IEEE:

In case helping (with e.g. PythonCall.jl): ibm2ieee Client Challenge

Hi @Palli, thank you for sharing the links, I am aware of them already. I am writing a new package that supports all SEGY revisions from revision 0.0 (before 1975) to revision 2.1 (2023). It is in very good shape already, except for the IBM float that is almost there.

1 Like

@matthias314 I am very happy with this implementation, thank you for the incredible help. Do you have any additional suggestion to improve readability or performance?

I understand that the only place where we are not doing explicit bit manipulation is the bias adjustment with eieee += 767. Is there an equivalent adjustment in terms of bit shifts?

Just a minor comment which may or may not be obvious to everyone.

If you have two (reasonably fast) implementations for this conversion and want to verify that they are doing the same thing, you can just run through all the 2^32 bit patterns.

5 Likes

You might find my package VaxData.jl helpful as a reference, since it sounds like you have similar goals supporting (reading, converting, etc) historic floating point representations.

2 Likes

The function ibm_to_ieee_64 is located in the file fp.c that is included in the zip file 3rd_Ed__NumbersAndComputers.zip in the repo, and the repo license file specifies the MIT license, so I think you are safe to publish the code.

4 Likes

For future reference: the solution I marked in this thread is ~10x faster than the one shared in the book (checked with BenchmarkTools.jl).

Thank you everyone for the help and for the additional links. This thread will certainly help future readers interested in this old floating point type.

1 Like

Even though this issue has been marked as solved, I’m going to add one more bit…

In May 2024, Cleve Moler, the famous numerical analyst and founder of Matlab, posted a blog entry on this same topic. He included a historical review, annotated sample Matlab codes, and a link to more robust Matlab codes (easily converted to Julia) that convert to/from IBM System/360 hexadecimal format, in both single and double precision. I obtained his permission to use these codes in other open-source software. So that is another good source of information on this topic.

4 Likes