二进制浮点数算术标准(IEEE口语读:I triple E),许多CPU和浮点运算器运用这种标准;这种标准下,浮点数无法保证小数部分十分精确,这也就是为什么有那个问题:0.1+0.2 != 0.3
IEEE 754转换器(32位):IEEE-754 Konverter für Fließkommazahlen
单精度浮点数(float,32位)
公式:(-1)S × 1.M × 2(E-127)
例如数字292.3,对应二进制表示:0 10000111 00100100010011001010000
首个位表示符号位S(sign),表示数字是正数还是负数,0表示正数,1是负数
中间八位表示指数E(exponent)
最后23位表示尾数M(mantisse)
计算过程:
符号位:-10 = 1
指数:100001112 = 13510 = 135 - 127 = 8,28= 256
尾数:

2-3 + 2-6 + 2-10 + 2-13 + 2-14 + 2-17 + 2-19 = 0.141794204711914
尾数部分隐含了一个1,个位是1,1+0.141794204711914 = 1.141794204711914
最后,1 * 1.141794204711914 * 256 = 292.29931640625
双精度浮点数(double,64位)
原理和32位相似。
公式:(-1)S × 1.M × 2(E-1023)
例如数字292.3456,对应二进制表示
:0 10000000111 0010010001011000011110010011110111011001011111110110
首个位表示符号位S(sign),表示数字是正数还是负数,0表示正数,1是负数
中间11位表示指数E(exponent)
最后52位表示尾数M(mantisse),这个部分的结果计算出来要+1,也就是个位数是1
计算过程:
符号位:-10 = 1
指数:100000001112 = 103110 = 1031 - 1023 = 8,28= 256
尾数(太长了,以下**符号是Javascript的幂运算符):
(2**-3+2**-6+2**-10+2**-12+2**-13+2**-18+2**-19+2**-20+2**-21+2**-24+2**-27+2**-28+2**-29+2**-30+2**-32+2**-33+2**-34+2**-36+2**-37+2**-40+2**-42+2**-43+2**-44+2**-45+2**-46+2**-47+2**-48+2**-50+2**-51)+1 = 1.141975
最后,1 x 1.141975 x 256 = 292.3456
有符号整数型的补码
有符号整数(可能有负号)用补码(two's complement)来表示
//数字5在int类型中的二进制:
0b000000000000000000000000 0000 0101
//-5的二进制,所有二进制位取反
0b111111111111111111111111 1111 1010
//然后+1
0b111111111111111111111111 1111 1011//数字100在int类型中的二进制:
0b000000000000000000000000 0110 0100
//-100的二进制,所有二进制位取反(补码表示)
0b111111111111111111111111 1001 1011
//然后+1
0b111111111111111111111111 1001 1100在int(有符号32位整数)类型中:
00000000000000000000000000000000 //所有位都是0表示0
0 1111111111111111111111111111111 //表示正数的最大数,也就是2147483647,0和31个1
//由此可见,第一位是类似符号位(sign),表示数值是正数还是负数,0表示正数,1表示负数
1 1111111111111111111111111111111 //表示-1
1 1111111111111111111111111111110 //表示-2
1 1111111111111111111111111111101 //表示-3
1 0000000000000000000000000000000 //int的最小值(INT_MIN),-2147483648
//INT_MIN再减1,就会发生截断:
0 1111111111111111111111111111111 //从INT_MIN成为了INT_MAX无符号整数型
所有比特位(所有字节)都用于表示数值
#include <iostream>
#include <bitset>
int main() {
char c1[4] = { 'A','B','C','D' };
unsigned int* i1 = reinterpret_cast<unsigned int*>(c1); //此处c1传入的是char*,是c1数组的首地址,将4个字节的char数组重新解释为uint32
std::cout << *i1 << std::endl; //1145258561
std::cout << std::bitset<32>(*i1) << std::endl; //01000100010000110100001001000001
}由于是小端序(little endian),所以得到的二进制位是反过来的:
| 01000100 | 01000011 | 01000010 | 01000001 |
(D) (C) (B) (A)为什么值为1145258561?计算过程:
01000100010000110100001001000001
从右向左,将每一位是1的值进行计算,第一个位置是0
1*20 = 1
1*26 = 64
1*29 = 512
1*214 = 16384
.........
1*230 = 1073741824
最后全部相加,得出来就是1145258561
c++技巧
二进制的浮点数赋值给double:
//直接将二进制0b010000...赋值给double效果会和想的不一样
//0b010000...字面量会先转变成long long再把结果的数字赋值给double
//以下会将ll1的逐字节拷贝到double变量中,也可以说拷贝的是比特位
unsigned long long ll1 = 0b0100000001110010010001011000011110010011110111011001011111110110;
double d;
memcpy(&d, &ll1, sizeof(ll1));
//或者:
unsigned long long ll1 = 0b0100000001110010010001011000011110010011110111011001011111110110;
double* d = reinterpret_cast<double*>(&ll1);
std::cout << *d << std::endl; //292.3456取出double的每个比特位:
#include <iostream>
#include <bitset>
#include <iomanip>
int main() {
double d1 = 292.3456;
uint64_t* ll1 = reinterpret_cast<uint64_t*>(&d1);
std::cout << std::bitset<64>(*ll1) << std::endl; //0100000001110010010001011000011110010011110111011001011111110110
}