单精度浮点数 float

浮点数在内存中的存储格式是 127 基偏差 方式 (base biased 127 encoding) 即将 -127 = 0x00000000 那么:

  • 1 = 0x10000000
  • 128 = 0x11111111
  • 0 = 0x01111111

小数点的前后

对于十进制小数 10.625, 我们可以将整数部分分解为二进制: 1010
但是小数部分如何用二进制表示?
类比十进制,小数点后一位是 10110^{-1}, 二进制小数点后一位是 212^{-1}, 二进制小数点后二位是 222^{-2}, 以此类推。
那么 .625 就可以理解为 0.5+0.125=21+23=0b0.1010.5 + 0.125 = 2^{-1} + 2^{-3} = 0b0.101
因此整个小数就是 0b1010.1010b1010.101 = 10.625

正规化 normalization

为了方便浮点数的运算,我们需要将小数点的位置规整化,类似于科学计数法,我们只将位数规整化为 x.xxxxx×2nx.xxxxx \times 2^n 的形式,这样就可以方便的进行加减乘除运算。
不过,在二进制科学计数法中,我们需要整数部分不为零,其值必为1,我们可以不用存储这一位数, 因此我们可以用更多的空间记录剩下的小数部分,在实际中我们分配了23位给小数精确度
再去掉一位给正负号 sign, 剩下 8 位我们分配给指数,这个指数部分采用 127 偏移的方式, 也就是范围为 101271012810^{-127} \sim 10^{128}

局限性

当我们用一个很大的数去加上一个很小的数的时候,例如 1000000+0.00011000000 + 0.0001, 我们用 float 进行计算就会将点对齐进行计算,但是由于存储位数有限,精度有限,可能会出现结果不准确的问题
如果要解决这个问题,我们就要引入 double 双精度浮点数,以牺牲性能的代价提高精度

双精度浮点数 double

  • 53 位精确度(小数部分), 约等于 16 位十进制小数 (float 的 24位精度为 7 位十进制小数)
  • 上限 1030810^{308}, 下限 1030810^{-308}, float 的上限 103810^{38}, 下限 103810^{-38} (指数部分多了3位)

用谁呢?

其实在大数据时代,精度很多时候并不是那么要紧,反而是运算速度(算力)肥肠的重要,特别是在机器学习的领域中,我们往往会为了更快的计算来弱化精度,因此 float 也是很常用的