Jacky's blog
首页
  • 学习笔记

    • web
    • android
    • iOS
    • vue
  • 分类
  • 标签
  • 归档
收藏
  • tool
  • algo
  • python
  • java
  • server
  • growth
  • frida
  • blog
  • SP
  • more
GitHub (opens new window)

Jack Yang

编程; 随笔
首页
  • 学习笔记

    • web
    • android
    • iOS
    • vue
  • 分类
  • 标签
  • 归档
收藏
  • tool
  • algo
  • python
  • java
  • server
  • growth
  • frida
  • blog
  • SP
  • more
GitHub (opens new window)
  • shell

  • tool

  • 网络

  • algo

  • compute_base

    • float的存储
      • 🔍 浮点数表示的基本原理
        • 二进制小数表示
        • 通用浮点数公式
        • 实例分析
      • 📊 IEEE754 标准详解
        • 单精度浮点数 (32位)
        • 双精度浮点数 (64位)
        • 🔢 数值计算公式
      • 📝 详细存储示例
        • 示例1:存储 12.375
        • 示例2:存储 -0.1875
      • ⚠️ 特殊值处理
        • 零值 (Zero)
        • 无穷大 (Infinity)
        • 非数值 (NaN - Not a Number)
        • 非规格化数 (Denormalized Numbers)
      • 🔧 实际应用和注意事项
        • 1. 精度损失问题
        • 2. 浮点数比较
        • 3. 范围和精度
      • 💡 实用工具和技巧
        • 1. 十进制转二进制算法
        • 2. IEEE754 格式解析
        • 3. 常见浮点数的存储
      • 🎯 实际编程中的应用
        • 1. 浮点数序列化
        • 2. 高精度计算
      • 📚 总结
      • 🔗 参考资料
    • RAM ROM
  • blog

  • growth

  • java

  • C&C++

  • ai

  • secure

  • cms

  • english

  • 生活

  • 金融学

  • more

  • other
  • compute_base
Jacky
2024-07-07
目录

float的存储

# 浮点数的存储机制详解

# 🔍 浮点数表示的基本原理

# 二进制小数表示

在计算机中,浮点数使用二进制科学计数法来表示。任何一个十进制小数都可以转换为二进制形式:

十进制: 1.8125
二进制: 1.1101
科学计数法: 1.1101 × 2^0
1
2
3

# 通用浮点数公式

任意一个二进制浮点数 V 可以表示为:

V = (-1)^S × M × 2^E

其中:

  • S (符号位):当 S=0 时,V 为正数;当 S=1 时,V 为负数
  • M (尾数/有效数字):大于等于 1,小于 2 的二进制小数
  • E (指数):指数位,用于表示数值的量级

# 实例分析

正数示例:

十进制: 5.0
二进制: 101.0
科学计数法: 1.01 × 2^2
因此: S=0, M=1.01, E=2
1
2
3
4

负数示例:

十进制: -5.0
二进制: -101.0
科学计数法: -1.01 × 2^2
因此: S=1, M=1.01, E=2
1
2
3
4

# 📊 IEEE754 标准详解

IEEE754 是国际电气电子工程师学会制定的浮点数表示标准,定义了浮点数在计算机中的存储格式。

# 单精度浮点数 (32位)

存储布局:

|  符号位  |    指数位    |        尾数位        |
|  1 bit   |   8 bits    |      23 bits        |
| 31       | 30      23  | 22               0  |
1
2
3
  • 符号位 (S):1位,表示正负
  • 指数位 (E):8位,范围 0-255,实际指数 = E - 127 (偏移量)
  • 尾数位 (M):23位,表示小数部分(隐含前导1)

# 双精度浮点数 (64位)

存储布局:

|  符号位  |     指数位     |           尾数位           |
|  1 bit   |   11 bits     |         52 bits           |
| 63       | 62        52  | 51                     0  |
1
2
3
  • 符号位 (S):1位
  • 指数位 (E):11位,范围 0-2047,实际指数 = E - 1023 (偏移量)
  • 尾数位 (M):52位

# 🔢 数值计算公式

规格化数值 (1 ≤ E ≤ 254 for float, 1 ≤ E ≤ 2046 for double):

V = (-1)^S × (1 + M/2^23) × 2^(E-127)    // 单精度
V = (-1)^S × (1 + M/2^52) × 2^(E-1023)   // 双精度
1
2

非规格化数值 (E = 0):

V = (-1)^S × (M/2^23) × 2^(-126)         // 单精度
V = (-1)^S × (M/2^52) × 2^(-1022)        // 双精度
1
2

# 📝 详细存储示例

# 示例1:存储 12.375

步骤1:转换为二进制

12.375 = 12 + 0.375

整数部分转换 (12):
12 ÷ 2 = 6  余数: 0
6  ÷ 2 = 3  余数: 0  
3  ÷ 2 = 1  余数: 1
1  ÷ 2 = 0  余数: 1
从下往上读取:1100 (二进制)

小数部分转换 (0.375):
0.375 × 2 = 0.75   → 整数部分: 0, 小数部分: 0.75
0.75  × 2 = 1.5    → 整数部分: 1, 小数部分: 0.5
0.5   × 2 = 1.0    → 整数部分: 1, 小数部分: 0.0 (结束)
从整数部分读取:0.011 (二进制)

结果:1100.011
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

步骤2:科学计数法

1100.011 = 1.100011 × 2^3

转换过程:
1. 将小数点左移3位,使整数部分为1
   1100.011 → 1.100011
2. 记录移动的位数作为指数:3
3. 标准化形式:1.100011 × 2^3
1
2
3
4
5
6
7

步骤3:提取各部分

符号位 S = 0 (正数)

指数计算:
实际指数 = 3
IEEE754偏移量 = 127 (单精度)
存储指数 = 3 + 127 = 130
130转换为二进制:10000010

尾数计算:
原始尾数:1.100011
去掉隐含的1:100011
补齐到23位:10001100000000000000000
1
2
3
4
5
6
7
8
9
10
11
12

步骤4:32位存储格式

0 10000010 10001100000000000000000
S    E                M
1
2

# 示例2:存储 -0.1875

步骤1:转换为二进制

0.1875 = 3/16 = 0.0011 (二进制)

详细转换过程:
0.1875 × 2 = 0.375  → 整数部分: 0, 小数部分: 0.375
0.375  × 2 = 0.75   → 整数部分: 0, 小数部分: 0.75
0.75   × 2 = 1.5    → 整数部分: 1, 小数部分: 0.5
0.5    × 2 = 1.0    → 整数部分: 1, 小数部分: 0.0 (结束)

从整数部分读取:0.0011 (二进制)
1
2
3
4
5
6
7
8
9

步骤2:科学计数法

0.0011 = 1.1 × 2^(-3)
1

步骤3:提取各部分

符号位 S = 1 (负数)
指数 E = -3 + 127 = 124 = 01111100 (二进制)
尾数 M = 1 (补齐23位) = 10000000000000000000000
1
2
3

步骤4:32位存储格式

1 01111100 10000000000000000000000
S    E                M
1
2

# ⚠️ 特殊值处理

# 零值 (Zero)

+0: S=0, E=0, M=0
-0: S=1, E=0, M=0
注意:+0 和 -0 在比较时相等
1
2
3

# 无穷大 (Infinity)

+∞: S=0, E=255(单精度)/2047(双精度), M=0
-∞: S=1, E=255(单精度)/2047(双精度), M=0
1
2

# 非数值 (NaN - Not a Number)

NaN: S=任意, E=255(单精度)/2047(双精度), M≠0
用于表示未定义的运算结果,如 0/0, √(-1)
1
2

# 非规格化数 (Denormalized Numbers)

当 E=0 且 M≠0 时,表示非常接近零的小数
用于填补最小规格化数和零之间的间隙
1
2

# 🔧 实际应用和注意事项

# 1. 精度损失问题

# Python 示例
print(0.1 + 0.2)  # 输出: 0.30000000000000004
# 原因:0.1 和 0.2 无法精确表示为二进制浮点数
1
2
3

# 2. 浮点数比较

// 错误的比较方式
if (a == b) { ... }

// 正确的比较方式
#define EPSILON 1e-9
if (fabs(a - b) < EPSILON) { ... }
1
2
3
4
5
6

# 3. 范围和精度

单精度 float (32位):

  • 范围:约 ±1.4 × 10^(-45) 到 ±3.4 × 10^38
  • 有效数字:约 7 位十进制数字

双精度 double (64位):

  • 范围:约 ±4.9 × 10^(-324) 到 ±1.8 × 10^308
  • 有效数字:约 15-17 位十进制数字

# 💡 实用工具和技巧

# 1. 十进制转二进制算法

def decimal_to_binary_fraction(decimal_part, precision=23):
    """将十进制小数部分转换为二进制"""
    binary = ""
    for _ in range(precision):
        decimal_part *= 2
        if decimal_part >= 1:
            binary += "1"
            decimal_part -= 1
        else:
            binary += "0"
    return binary

# 示例
print(decimal_to_binary_fraction(0.375))  # 输出: "011"
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 2. IEEE754 格式解析

import struct

def analyze_float(f):
    """分析浮点数的IEEE754表示"""
    # 获取32位二进制表示
    bits = struct.unpack('I', struct.pack('f', f))[0]
    
    # 提取各部分
    sign = (bits >> 31) & 1
    exponent = (bits >> 23) & 0xFF
    mantissa = bits & 0x7FFFFF
    
    print(f"数值: {f}")
    print(f"符号位: {sign}")
    print(f"指数位: {exponent} (实际指数: {exponent - 127})")
    print(f"尾数位: {mantissa:023b}")
    print(f"完整二进制: {bits:032b}")

# 示例
analyze_float(12.375)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 3. 常见浮点数的存储

十进制 单精度IEEE754 说明
0.0 00000000 00000000 00000000 00000000 正零
-0.0 10000000 00000000 00000000 00000000 负零
1.0 00111111 10000000 00000000 00000000 1
-1.0 10111111 10000000 00000000 00000000 -1
+∞ 01111111 10000000 00000000 00000000 正无穷
-∞ 11111111 10000000 00000000 00000000 负无穷
NaN 01111111 1xxxxxxx xxxxxxxx xxxxxxxx 非数值

# 🎯 实际编程中的应用

# 1. 浮点数序列化

// 将浮点数转换为字节数组
union FloatBytes {
    float f;
    unsigned char bytes[4];
};

void serialize_float(float value, unsigned char* buffer) {
    union FloatBytes fb;
    fb.f = value;
    memcpy(buffer, fb.bytes, 4);
}
1
2
3
4
5
6
7
8
9
10
11

# 2. 高精度计算

from decimal import Decimal, getcontext

# 设置高精度
getcontext().prec = 50

# 使用 Decimal 避免浮点数精度问题
a = Decimal('0.1')
b = Decimal('0.2')
result = a + b  # 精确结果:0.3
1
2
3
4
5
6
7
8
9

# 📚 总结

IEEE754浮点数存储标准是现代计算机处理实数的基础,理解其原理对于:

  • 避免精度陷阱:理解为什么某些十进制数无法精确表示
  • 优化数值计算:选择合适的数据类型和算法
  • 调试浮点数问题:快速定位和解决浮点数相关的bug
  • 跨平台数据交换:确保浮点数在不同系统间的一致性

掌握浮点数存储机制是每个程序员必备的计算机基础知识!

# 🔗 参考资料

  • IEEE754标准官方文档 (opens new window)
  • 浮点数在计算机中是如何存储的? (opens new window)
  • What Every Programmer Should Know About Floating-Point Arithmetic (opens new window)
  • IEEE754 在线转换器 (opens new window)
#浮点数#IEEE754#计算机基础
上次更新: 2025/09/21, 20:21:23
算法面试指南
RAM ROM

← 算法面试指南 RAM ROM→

最近更新
01
npx 使用指南
10-12
02
cursor
09-28
03
inspect
07-20
更多文章>
Theme by Vdoing | Copyright © 2019-2025 Jacky | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式