Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C

Transform between IEEE, IBM or VAX floating point number formats and bytes expressions

4.74/5 (14 votes)
21 Nov 20056 min read 1   1.9K  
This program can transform between IEEE, IBM or VAX floating point number formats and their bytes expressions.

Introduction

This program can transform a floating point number to its bytes expression or transform a bytes expression to a floating point number.

Background

Have you ever tried to develop a program to read a DLIS (Digital Log Interchange Standard) format data file? I found that the sample log data was recorded as VAX single float format. So, I had to read a 4 bytes stream from the binary file, and then recover the real number. I succeeded to recover all the frame data for all the channels. I compared my result with the output of the Schlumberger free tool program, Toolbox. They were identical. I also did some test using a free Java package, Cynosurex, and it gave the same result. This reminded me some of some halfway jobs I did about floating point number and bytes order analysis five years ago, and inspired my enthusiasm to proceed again.

Bits expression of floating point number

IEEE single precision floating point:

SEF :    S        EEEEEEEE        FFFFFFF        FFFFFFFF        FFFFFFFF
bits :   1        2      9        10                                    32
bytes :  byte1           byte2                   byte3           byte4

IEEE double precision floating point:

SEF:   S     EEEEEEE EEEE  FFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
bits:  1     2          12 13                                                       64
bytes: byte1         byte2      byte3    byte4    byte5    byte6    byte7    byte8
frctn.:                    L1                     L2

IBM single precision floating point:

SEF :       S        EEEEEEE        FFFFFFFF        FFFFFFFF        FFFFFFFF
bits :      1        2     8        9                                      32
bytes :     byte1                   byte2           byte3           byte4

IBM double precision floating point:

SEF:   S     EEEEEEE  FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
bits:  1     2     8  9                                                            64
bytes: byte1          byte2    byte3    byte4    byte5    byte6    byte7    byte8
frctn.:               L1                         L2

VAX single precision floating point:

SEF :       S        EEEEEEEE        FFFFFFF        FFFFFFFF        FFFFFFFF
bits :      1        2      9        10                                    32
bytes :     byte2           byte1                   byte4           byte3

General encoding formula of the floating point

V = (-1)<SUP>S</SUP> * M * A<SUP>( E - B )</SUP>
M = C + F

V is the value, S is the sign, M is called mantissa, A is base, E is exponent, B is exponent bias, C is mantissa constant, and F is fraction. A, B and C are constants that could be different with the floating point architecture. Here are some of them:

IEEE single float :     A = 2   B = 127   C = 1
IEEE double float :     A = 2   B = 1023  C = 1
IBM  single float :     A = 16  B = 64    C = 0
IBM  double float :     A = 16  B = 64    C = 0
VAX  single float :     A = 2   B = 128   C = 0.5

Maximum value of the fraction

As mentioned above, F is the fraction. The minimum value of the IEEE and VAX fraction F is 0, and IBM fraction minimum value is 1/16. F is zero means all fraction bits (F of the bits expression above ) are 0. The maximum value of the fraction will be reached when all fraction bits are 1. To figure out it, we have to use a little high school mathematics, can you remember this formula?

1/2 + 1/4 + 1/8 + ... + 1/2<SUP>n</SUP> = 1 - 1/2<SUP>n</SUP>

The only easy ignored detail here is about the VAX single precision floating point. Except its wired bytes order, its fraction bits segment starts from 1/4, not from 1/2 as IEEE or IBM. This is another example for that complexity is always from personality.

G is the maximum value of the fraction F

IEEE single float :     G = 1 - 1/2<SUP>23</SUP>
IEEE double float :     G = 1 - 1/2<SUP>52</SUP>
IBM  single float :     G = 1 - 1/2<SUP>24</SUP>
IBM  double float :     G = 1 - 1/2<SUP>56</SUP>
VAX  single float :     G = 1 - 1/2<SUP>24</SUP> - 1/2

Mantissa range

It is easy to figure out the mantissa range based on the above values of C and G. The IBM float mantissa minimum value will be explained below.

IEEE single float :     1 <= M <= 2 - 1/2<SUP>23</SUP>
IEEE double float :     1 <= M <= 2 - 1/2<SUP>52</SUP>
IBM  single float :     1/16 <= M <= 1 - 1/2<SUP>24</SUP>
IBM  double float :     1/16 <= M <= 1 - 1/2<SUP>56</SUP>
VAX  single float :     1/2 <= M <= 1 - 1/2<SUP>24</SUP>

Bytes order

I use a simple union data structure and a two bytes unsigned short integer 258 to find the kind of bytes order for your memory to store the number. For Little Endian architecture, such as: Intel, this function will return 2; for Big Endian architecture, such as: SPARC, this function will return 1.

Transform bytes to floating point

There are two steps for the transformation. The first step is to transform bytes to SEF, which means Sign, Exponent, and Fraction. The second step is to transform SEF to a floating point number.

1. Bytes to SEF:

Firstly, adjust the incoming bytes order to fit the above bits expression of floating point, then the SEF values can be gotten through some bits operation based on the above bits expression. For double precision floating point, I decompose the fraction into two parts: two unsigned long integers, which are L1 and L2.

2. SEF to floating point:

It is easy to recover the floating point number from SEF based on the above general encoding formula and the three constants A, B and C.

Transform floating point to bytes

Similar with the above method, there are two steps for the transformation. The first step is to transform the floating point to SEF. The second step is to transform SEF to bytes.

1. Floating point to SEF:

This part is the most important in all programs. I developed two methods to calculate the E and F from the floating point number.

The first method is more natural. Its principle is same as transforming an integer to its binary expression, which gets every bit through continually dividing the base 2. In our case, we can continually divide or multiply the base till the quotient settles within the mantissa range mentioned above. The choice of divide or multiply depends on whether the value E-B is positive or negative, but it is impossible to know the sign of the value E-B before E is known. Actually, we can determine it through comparing the floating point number with the mantissa bound value. The loop times is used to determine the E value, meantime, the surplus value of the original floating point after the loop is used to determine the F value.

The second method is a little complex. It uses the reverse algorithm to figure out the E value by the logarithm, then it is easy to get the F value by the above encoding formula. Actually, we can conclude the following formula for E and F:

V is the floating point number
D = log2 , base is e

IEEE single float :     E = (int) ( logV / D + B )
IEEE double float :     E = (int) ( logV / D + B )
IBM  single float :     E = (int) ( ( logV / D ) / 4 + 1 + B )
IBM  double float :     E = (int) ( ( logV / D ) / 4 + 1 + B )
VAX  single float :     E = (int) ( ( logV / D ) + 1 + B )

F = V / A<SUP>(E-B)</SUP> - C

I will give a brief proof for these formulae. The zero value and the sign S can be harmlessly ignored, so the float value is assumed as positive: V > 0.

  1. IEEE float:

    The mantissa range of the IEEE float is: 1 <= M < 2 . So: 0 <= logM / log2 < 1. Notice: E is a non-negative integer, so:

      (int) ( logV / log2 + B )
    = (int) ( logM / log2 + ( E-B ) + B )
    = (int) ( logM / log2 + E )
    = E
    
  2. IBM float:

    The key point here is mentioned in the RP66 reference document: Bits 1 - 4 of byte 2 may not all be zero except for true zero. In other words, the first hexadecimal digit of the mantissa must be non-zero, except for true zero. This means the IBM float mantissa minimum value is 1/16. So: 0 < logM / log16 + 1 < 1. Notice: E is a non-negative integer.

      (int) ( ( logV / log2 ) / 4 + 1 + B )
    = (int) ( logM / log16 + ( E-B ) + 1 + B )
    = (int) ( logM / log16 + 1 + E )
    = E
    
  3. VAX float:

    The VAX float mantissa minimum value is 1/2, so: 0 < logM / log2 + 1 < 1. Notice: E is a non-negative integer.

      (int) ( logV / log2 + 1 + B )
    = (int) ( logM / log2 + ( E-B ) + 1 + B )
    = (int) ( logM / log2 + 1 + E )
    = E
    

2. SEF to bytes

There are no difficult things for this part. It just needs bytes order adjustment and some bits operation.

The programs also include a regular Union method to transform an IEEE float and its bytes expression.

Compile

This program was compiled in the MinGW environment in Windows-XP. You have to set the PATH environment variable or run setp.bat before compiling.

set PATH = %PATH%; C:\MinGW\bin ;

Then run clib.bat to create the library, or manually compile the program as follows:

del libNumber.lib
del *.o
g++ -c ByteOrder.c
g++ -c Float2SEF.c
g++ -c SEF2Byte.c
g++ -c Byte2SEF.c
g++ -c SEF2Float.c
g++ -c IeeeFloat.c
g++ -c IbmFloat.c
g++ -c VaxFloat.c
g++ -c TestlibNumber.c
ar m libNumber.lib
ar r libNumber.lib *.o
ar t libNumber.lib
del *.o

Run cpsam.bat to compile the two test programs as follows:

cpsam test1
cpsam test2

After all, you can run the test1.exe program in a DOS window. You also can redirect the output to a text file as follows:

test1 > test.txt

test2.exe is another test program to test any float number for this library.

Reference

I have wrapped all reference web pages into my source code Zip package.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here