I knew two years ago not to use the = = number to judge the floating-point numbers equal, because there is a problem of precision, but all along, not how to care about these things, and in fact, I am the structure of floating point, although understanding, but not clear. As a C + + enthusiast, you should try to figure out every problem, so I figured out the intrinsic expression and implementation of floating-point numbers. In the absence of big problems, everything is easy to understand and remember as the standard.
First of all, the original, reverse, complement, shift code. The shift code is actually equal to the complement, only the symbol opposite. For positive numbers, the original, reverse, and complement are the same, for negative numbers, anti-code in addition to the symbol bit, in the original code based on the position of the reverse, the complement is on the basis of anti-code, in its lowest level plus 1, the need to move the code, is still the first complement, and then change the symbol.
Floating-point numbers are divided into float and double, accounting for 4, 8 bytes, or 32, 64 bits, respectively. I only take the 32-bit float for example, and it comes with double.
In the IEEE754 standard, the 32 bits of float are stated as follows:
Sign Bit (S) 1 |
Order Code (E) 8 |
Mantissa (M) 23 |
Here should pay attention to three points: A, the order code is represented by a shift code, here there will be a 127 offset, its 127 is equivalent to 0, less than 127 is negative, more than 127 is positive, for example: 10000001 means the exponent is 129-127=2, indicating the true value of 2^2, and 01111110 represents 2^ (-1).
B, the mantissa is all the number after the decimal point,
C, but a 1 is omitted in the mantissa, so the mantissa is all 0 o'clock and 1.0 ... 00;
Next, just explain a few questions to understand, take 123.456 as an example, expressed as binary is: N (2) = 1111011. 01110100101111001, here, will move right 6 bits, get N (2) = 1.111011 01110100101111001*2^6; This form can be used in the representation format.
Sign Bit (S) 0 |
Order Code (E) 00000110 |
Mantissa (M) 11101101110100101111001 |
Notice that the first bit of the above code is 0 table, the mantissa is less than the first digit of N (2) is 1, which is the default is the first bit 1. As the decimal into the binary process, often can not just turn equal, (of course, like 4.0 so there will be no loss, and 1.0/3.0 such an inevitable loss), so the problem of the accuracy of floating-point numbers, in fact, the 23-bit binary number after the decimal point, can affect the decimal number of the first 8 bits, What is this for? The average person at this time often fascinated hoo hoo, in fact, is very simple, in the mantissa indicated above, is the binary, after the decimal point there are 23, the last one of the value of 1 o'clock, it is 1/2^22=0.000000238 actually take when it must be 0.0000002, that is, For a float-type floating-point number, the valid number of digits is 7 bits from left to right (including the default of 1 is 7 bits), when it reaches the 8th position above, it is not reliable, but our VC6 can output the longest 1.0/3.0 0.33333333333333331, This is mainly a compiler problem, not that the floating point number after the decimal point 16 are valid . if you do not believe, you can try a double type of 1.0/3.0, will be the decimal point after the 17-bit . . In addition, the compiler or the circuit board generally have "de-noise" of the "correction" ability, it can make more than 7 decimal number even if invalid, it will not become outrageous, this is why the above is always output 333 instead of 345 and so on. You can try this:
float f=123456789;
cout<<f<<endl;//here must get 123456789.
Here is a forgotten question, that is 10 decimal how to change into 2 decimal, in fact, it is very simple, is to multiply 10 decimal parts multiplied by 2, carry the corresponding 2 bits to write 1. So the above n (2) = 1.111011 01110100101111001*2^6, and then back to the decimal number, is probably no longer 123.456. OK, the accuracy of the problem should be clearly explained. The following is an example of a range.
The number of digits of the order is 8-bit shift code, the maximum is 127 the minimum is-127, here 127 is used as the exponent of 2, so is 2^127, approximately equal to 1.7014*10^38, and we know that the range of float is about -3.4*10^38-------3.4*10^ 38, this is because the 24 bits of the mantissa (the default first bit is 1) are all 1, very close to 2, the 1.11..11 is obviously about 2, so the range of floating-point numbers is out.
The case of double is exactly like float, except that its intrinsic form is
Sign Bit (S) 1 |
Order Code (E) 11 |
Mantissa (M) 52 |
The main difference is that it has a 11-bit order code, which has a 2^1023 about equal to 0.8572*10^308, the Mantissa 53 bits is about 2, so the range of double is about -1.7*10^308.------1.7*10^308. As for its accuracy, likewise, 1.0/2^51=4.4*10^ (-16). 15 digits after the decimal point are valid, plus the default one, so that for double floating-point numbers, the 16-digit number from left to right is reliable.
Sometimes, we will hear the word "fixed-point decimal", single-chip microcomputer (such as mobile phones, etc.) generally only use fixed-point number, confused, we will think of float a=23.4; This is a fixed-point decimal, float a=2.34e1 This is a floating-point number, in fact, this is wrong, above is just the same floating point of different representations, are floating-point numbers. Fixed-point decimal is the formulation, that the whole is fixed-point decimal, the decimal point is set in the rear, the fractional part is divided into 0. You can also think of decimal fraction as a fixed-point decimal, but it can only represent decimal fraction less than 1.
Then say a few of the functions in C/s + +, the default output of C + + 5 decimal places, but can be set, there are two ways: call setpression or use cout.pression, but the effect is different:
float mm=123.456789f;
cout<<mm<<endl; 123.457 Although the default is not a number of the last 5 bits, but only the integer part only one.
Setprecision (10); Sets the number of digits after the decimal point, but when the integer portion has two bits, it is no different from the default, and does not work.
cout<<mm<<endl; 123.457
Cout.precision (4); Sets the total number of digits.
cout<<mm<<endl; 123.4 in short, the effect is rather strange, personally think that although this is not enough certainty, but the actual hardware system is limited. It's understandable.
For the actual representation of 0, it was thought that +0 would generally be 0, while 0 would represent a very small number. To this end, I think of a good verification method, proof whether +0 or 0, it is 2^ (-127), the code is as follows:
float fdigital = 0.0f;
unsigned long nmem;//temporary variable for storing floating-point memory data
The memory bit is copied to the temporary change in order to fetch, at this time the nmem is not equal to fdigital, it is a bitwise copy.
Nmem = * (unsigned long*) &fDigital;
cout<<nmem<<endl; Generally get a very large integer.
Bitset<32>mybit (NMEM);//Wonderful here, the output here is the memory representation of 32float. Finally, it's completely intuitive to see.
cout<<mybit<<endl; 00000000000000000000000000000000 with-0.0来 try, too.
If you still think that the long list of 0 above means absolute 0, please look at this article again. In fact, my practice is quite ingenious, the above fdigital with any other floating point, the Bitset number can reflect its memory representation.
There is a reason for the shift code to express the order code, mainly to move the code to facilitate the operation of the order, thus comparing the size of two floating-point numbers. It is important to note that the order code cannot reach 11111111, and the IEEE stipulates that when the compiler encounters a 0XFF order, the overflow instruction is called. In summary, when the order is integer, the range is: -127~127.
Finally, there is often a master also ashamed of the place, be sure to remember that floating point number without unsigned usinged float/double is wrong.
I Caishuxueqian and welcome criticism.
Floating-point representation and its implementation