1

I am a reading binary file and trying to convert from IBM 4 Byte floating point to double in C++. How exactly would one use the first byte of IBM data to find the ccccccc in the given picture

IBM to value conversion chart

The code below gives an exponent way larger than what the data should have. I am confused with how the line

exponent = ((IBM4ByteValue[0] & 127) - 64);

executes, I do not understand the use of the & operator in this statement. But essentially what the previous author of this code implied is that (IBM4ByteValue[0]) is the ccccccc , so does this mean that the ampersand sets a maximum value that the left side of the operator can equal? Even if this is correct though I'm sure how this line accounts for the fact that there Big Endian bitwise notation in the first byte (I believe it is Big Endian after viewing the picture). Not to mention 1000001 and 0000001 should have the same exponent (-63) however they will not with my current interpretation of the previously mentioned line.

So in short could someone show me how to find the ccccccc (shown in the picture link above) using the first byte --> IBM4ByteValue[0]. Maybe accessing each individual bit? However I do not know the code to do this using my array.

**this code is using the std namespace **I believe ret should be mantissa * pow(16, 24+exponent) however if I'm wrong about the exponent I'm probable wrong about this (I got the IBM Conversion from a previously asked stackoverflow question) **I would have just commented on the old post, but this question was a bit too large, pun intended, for a comment. It is also different in that I am asking how exactly one accesses the bits in an array storing whole bytes.

Code I put together using an IBM conversion from previous question answer

for (long pos = 0; pos < fileLength; pos += BUF_LEN) {
    file.seekg(bytePosition);
    file.read((char *)(&IBM4ByteValue[0]), BUF_LEN);
    bytePosition += 4;
    printf("\n%8ld:  ", pos);

    //IBM Conversion
double ret = 0;
uint32_t mantissa = 0; 
uint16_t exponent = 0;
mantissa = (IBM4ByteValue[3] << 16) | (IBM4ByteValue[2] << 8)|IBM4ByteValue[1];
exponent = ((IBM4ByteValue[0] & 127) - 64);
ret = mantissa * exp2(-24 + 4 * exponent);
if (IBM4ByteValue[0] & 128) ret *= -1.;

printf(":%24f", ret);
printf("\n");
system("PAUSE");

}

CrippledTable
  • 784
  • 5
  • 20
  • x&127 sets the highest bit to zero. So, for a binary number Xabcdefg&127=0abcdefg. For the examples you mentioned (1000001 and 0000001), &'ing with 127 creates the number 00000001. (assuming that you mistyped the numbers - these only have 7 digits, so I assume that you meant 10000001) – geza Jul 25 '17 at 20:24
  • btw, would you mind telling us your usage scenario? I'm interested in such kind of things: https://stackoverflow.com/questions/45119928/c11-c14-on-exotic-hardware – geza Jul 25 '17 at 20:45
  • Makes sense, thanks. Does that mean that &63 would set the two highest bits to zero? – CrippledTable Jul 25 '17 at 20:53
  • I'm creating an application/converting an application from Delphi to C++ that takes seismic traces in SEGY formats and displays them in a GUI – CrippledTable Jul 25 '17 at 20:54
  • Yep. Bit arithmetic is basic stuff, you might want to check them out :) Thanks for telling the usage scenario! – geza Jul 25 '17 at 21:00
  • http://www.learncpp.com/cpp-tutorial/38-bitwise-operators/ now it's very concrete. Thanks for the suggestion – CrippledTable Jul 25 '17 at 21:17

1 Answers1

0

The & operator basically takes the bits in that value of the array and masks it with the binary value of 127. If a bit in the value of the array is 1, and the corresponding bit position of 127 is 1, the bit will be a resulting 1. 1 & 0 would be 0, and so would 0 & 0 , and 0 & 1. You would be changing the bits. Then you would take the resulting bit value, converted to decimal now, and subtract 64 from it to equal your exponent.

In floating point we always have a bias (in this case, 64) for the exponent. This means that if your exponent is 5, 69 will be stored. So what this code is trying to do is find the original value of the exponent.

  • It seems that IBM doesn't use IEEE754, but some other format. So here, bias is not 127, but 64. – geza Jul 25 '17 at 20:19
  • I completely understand how to exponent line works now, and it plays nicely 90% of the time (values between 0-63). However every now and then it gets a 60,000+ number. Which makes absolutely no sense to me. I know the file I'm reading is in binary data. and I've used the read functions to read data correctly that isn't in the IBM format. So this bug is really perplexing. – CrippledTable Jul 25 '17 at 21:25
  • @GabbyQuattrone any ideas? – CrippledTable Jul 26 '17 at 14:58
  • 1
    It's important to understand how floating point is stored. I know in Intel x86 structure, floating point is stored in 32 bits. The 31st bit (start from 0) holds the sign. 1(-) negative, and 0(+) positive. Bits 30-23 hold the exponent, which in your case has a bias of 64, acc. to @gesa. Bits 23-0 hold the mantissa, i.e all the numbers behind the leading one in float binary. This is important. Example: 5 in binary is 101. In floating point, 1.01 * 2^2 (Using base two) The leading 1 is NOT stored. You should write out what you are converting and check if you are masking and storing correctly. – knowledge_is_power Jul 26 '17 at 16:21
  • 1
    If you're converting to a double, make sure you're storing everything in the right bit spots. See: https://stackoverflow.com/questions/13542944/how-many-significant-digits-have-floats-and-doubles-in-java – knowledge_is_power Jul 26 '17 at 19:17