IEEE - 754 - find signbit, exponent, frac, normalized, etc

99封情书 提交于 2019-12-04 17:18:24

For a single precision number the high bit is the sign, the next 8 bits are the exponent and the remaining 23 bits are the mantissa. So...

bool negative = !!(HexNumber & 0x80000000);
int exponent = (HexNumber & 0x7f800000) >> 23;
int mantissa = (HexNumber & 0x007FFFFF);

If the exponent is 255, the number is either +- infinity or NaN depending on whether the mantissa is zero (0 means infinity). If the exponent is zero then ether the number is +- zero (if the mantissa is zero) or the mantissa is the actual unnormalized fractional value.

If the exponent is anything else, there is a hidden one bit on the top of the fraction, making it 24 bits. In this case, the actual exponent can be calculated by subtracting 127 from the exponent so that it is in the range -127 to +127, the power of two exponent.

To check whether your code is right here is a converter applet http://www.h-schmidt.net/FloatApplet/IEEE754.html

I Found the Applet was useful to check some values.

& does a bit-by-bit and operation between two values. If one of the values is a constant & has some useful properties.

  A | B | A & B 
 ---+---+------- 
  0 | 0 | 0 
  0 | 1 | 0 
 ---+---+------- 
  1 | 0 | 0 
  1 | 1 | 1 

As you can see in the truth table, the first two rows show that if A = 0, A & B = 0. Thus, putting a zero in a mask at some position has the effect of clearing that bit.

The last two rows show that if A = 1, A & B = B. Thus, putting a one in a mask at some position has the effect of passing that bit.

So you can use constant mask to clear the bits outside a known field.

You can do the same exercise with OR (|) and XOR (^) and conclude that a mask for use with | has the effect of setting the bits of a value where the mask is 1. ^ has the effect of toggling the bits of a value where the mask is 1.

/* in response to comment*/

It's not an exponent bit it's an exponent field that is 8-bits long. So, if you build your mask as follows:

0111 1111 1000 0000 0000 0000 0000 0000  (mask === 0x7F800000)
1011 1010 0101 0110 0110 1010 1001 1010  (value)
-------------------------------------------------
0011 1010 0000 0000 0000 0000 0000 0000   (result)

You can see here that all that is left over from this operation are the bits that composed the exponent field (namely 01110100). Now if you wanted to know the value of the field, you would need to shift the result to the right by the required amount. The required amount is (in general) the zero-indexed bit position of the least significant bit of the field. For the exponent field the required shift amount is 23.

On a side note, you have to be careful when shifting to the right. We can get away with it here because we know our mask has a zero in the most significant bit, but if that were not the case we would be wise to cast our result to an unsigned value before shifting to the right. If you don't you get sign extension.

int8_t exponent = ((uint32_t) (value & 0x7F800000)) >> 23; 
// the cast is not necessary in this case because the mask has a 0 in the msb

If you wanted to extract the sign bit, this cast would become important:

int8_t sign = ((uint32_t) (value & 0x80000000)) >> 31; 

(I don't know where you got the notion that you would have to shift by 8 to extract the sign bit)

In addition to the bit twiddling you're already considering, there are some library functions that allow you to dissect and scale floating point numbers.

If you have a float or double in hand, you can use std::frexp() to determine its significand (or mantissa) and exponent. The exponent will be integral, but the significand will be a real number either between 0.5 and 1 or zero.

icelated asked:

Can someone explain what is going on here? Where are we coming up with the &numbers?

The & operator is the bitwise AND operator. The hex numbers are bit masks, by applying the & operator with the appropriate mask, you can isolate the bits you are interested in.

@vicatcu, or anyone else this is

icelated..

The IEEE single precision floating point standard representation requires a 32 bit word, which may be represented as numbered from 0 to 31, left to right. The first bit is the sign bit, the next eight bits are the exponent bits, and the final 23 bits are the fraction.

Therefore to extract the sign bit we use the appropriate mask and shift by 31 to get the sign at the end? In addition to get the value of the exponent. since, its 8 bits in length - we shift 31 - 8(23) to shift it to the end? If true then the mantissa requires no shifting? Also, to extract the value we use the mask. This part confuses me. I think the mask is the hexadecimal equivelent. How do we come up with that hex number? ex: int exponent = (HexNumber & 0x7f800000) THANK YOU - i think i am getting this....

code revised:

#include <stdio.h>
 #include <stdlib.h>

int main(int argc, char *argv[])
{


int HexNumber;




int a = 0x12345678;
unsigned char *c = (unsigned char*)(&a);
if (*c == 0x78)
{
  printf("\nlittle-endian\n");
}
else
{
  printf("\nbig-endian\n");
}

printf("\n>");
scanf("%x", &HexNumber);
printf("\n%#x",HexNumber);


 bool negative = !!(HexNumber & 0x80000000);
 int exponent = (HexNumber & 0x7f800000) >> 23;
 int mantissa = (HexNumber & 0x007FFFFF);


 printf("\nsignBit %d,", negative);
 printf("expbits %d,", exponent);
 printf("fractbits %#x,", mantissa);




return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!