浮点数
以 float32 为例,其存储 32bits 由以下三部分(1+8+23=32
)组成
- 符号位,1 位
- 指数(偏移量)位,8 位。
- 对于
float32
,偏移量是 127
- 对于
- 尾数位,23 位
以 0.5 为例
首先递归乘以 2 得到尾数位的表示
标准化形式
0.5 可以表示为 1.00000000000*2^-1
- 符号位。
- 0.5 正数,浮点位为 0.5
- 指数(偏移)位,8 位。
- 存储指数 = 实际指数+偏移量 = −1+127=126(10) = 01111110(2)
- 尾数位,23 位
- 由于在 标准化表示
1.00000000000*2^-1
中,尾数位为全 0
- 由于在 标准化表示
以 123.0678
为了表示浮点数 123.0678 在 IEEE 754 标准下的二进制表示,我们需要将其转换为二进制形式并拆分为符号位、指数位和尾数位。我们以 float32
(单精度浮点数)为例进行说明。
步骤 1: 转换为二进制
首先,将 123.0678 转换为二进制形式:
-
整数部分 123 的二进制表示是: 123₁₀ = 1111011₂
-
小数部分 0.0678 的二进制表示通过不断乘以 2 取整得到。
0.0678 × 2 = 0.1356 (取整 0) 0.1356 × 2 = 0.2712 (取整 0) 0.2712 × 2 = 0.5424 (取整 0) 0.5424 × 2 = 1.0848 (取整 1) 0.0848 × 2 = 0.1696 (取整 0) 0.1696 × 2 = 0.3392 (取整 0) 0.3392 × 2 = 0.6784 (取整 0) 0.6784 × 2 = 1.3568 (取整 1) 0.3568 × 2 = 0.7136 (取整 0) 0.7136 × 2 = 1.4272 (取整 1) 0.4272 × 2 = 0.8544 (取整 0) 0.8544 × 2 = 1.7088 (取整 1) 0.7088 × 2 = 1.4176 (取整 1)
所以 0.0678 的二进制近似表示是 0.0000101101000101...。
因此,123.0678 的二进制近似表示是: 1111011.0000101101000101...
步骤 2: 标准化
将这个二进制数标准化为 1.尾数位 × 2^指数 的形式: 1111011.0000101101000101... = 1.1110110000101101000101... × 2^6
步骤 3: 确定指数位
对于 float32
,偏移量是 127,所以指数部分是 6 + 127 = 133,即 10000101(8 位二进制)。
步骤 4: 确定尾数位
尾数位是标准化后的小数部分 1110110000101101000101...,取前 23 位: 11101100001011010001010
步骤 5: 确定符号位
符号位是 0,因为 123.0678 是正数。
最终结果
将符号位、指数位和尾数 位组合在一起,得到 float32
类型的二进制表示:
0 10000101 11101100001011010001010
转换成十六进制表示: 0x42f606aa
因此,浮点数 123.0678 在 float32
(单精度浮点数)中的表示是 0x42f606aa
。
在计算机中使用浮点数表示一个具体的十进制数时,可能会引入误差。这是因为浮点数的二进制表示不能精确地表示所有的十进制数。让我们具体看看如何用 float32
和 float64
表示 123.0678,并计算它们的误差。
float 在表示 123.0678 时误差怎么表述
在 Python 中,浮点数默认使用的是双精度浮点数(float64
),因此当你定义一个浮点数 original_value = 123.0678
时,它实际上是以 float64
的精度存储的。我们可以通过计算这个值与其二进制表示的实际值之间的差异来确定误差。
1. float32
表示 123.0678 的误差
float32
使用 1 位符号位、8 位指数位和 23 位尾数位。
计算步骤:
- 转换为二进制:将 123.0678 转换为二进制表示。
- 标准化:将二进制表示标准化为 1.xxxx 的形式。
- 截断或舍入:由于尾数只有 23 位,需要截断或舍入多余的位。
- 重构为十进制:将标准化后的二进制数转换回十进制,计算误差。
实际计算中,可以使用编程语言(如 Python)来获得近似值和误差。
import numpy as np
# 原始值
original_value = 123.0678
# 使用 float32 表示
float32_value = np.float32(original_value)
# 计算误差
error_float32 = original_value - float32_value
print(f"Original value: {original_value}")
print(f"Float32 value: {float32_value}")
print(f"Error (Float32): {error_float32}")
运行上述代码,得到:
Original value: 123.0678
Float32 value: 123.06780242919922
Error (Float32): -2.4291992197151184e-06
2. float64
表示 123.0678 的误差
float64
使用 1 位符号位、11 位指数位和 52 位尾数位。
同样地,可以使用编程语言来获得近似值和误差。
# 使用 float64 表示
float64_value = np.float64(original_value)
# 计算误差
error_float64 = original_value - float64_value
print(f"Original value: {original_value}")
print(f"Float64 value: {float64_value}")
print(f"Error (Float64): {error_float64}")
运行上述代码,得到:
Original value: 123.0678
Float64 value: 123.0678
Error (Float64): 0.0
总结
- Float32:表示 123.0678 时会有一个小的误差,大约为
\(-2.4291992197151184 \times 10^{-6}\)
。 - Float64:表示 123.0678 时误差非常小,可以忽略不计。
这表明 float64
在表示精度上要优于 float32
,但在大多数情况下,float32
的误差也是可以接受的,具体取决于应用的需求。
Python 中的 decimal
Python 的 decimal
模块提供了一种用于浮点数的高精度表示法,称为十进制浮点数(Decimal Floating Point)。与二进制浮点数不同,十进制浮点数使用十进制(base-10)来表示数值,这样可以避免许多由二进制浮点数表示法引起的精度问题,特别是在处理十进制数时。
Decimal 模块的表示方法
decimal
模块中的十进制浮点数由三部分组成:
- 符号位:表示数值的正负。
- 系数(Coefficient):一个整数部分和小数部分的组合,用十进制表示。
- 指数(Exponent):一个整数,表示系数应该乘以10的多少次方。
这种表示法类似于科学计数法,但使用十进制基数而不是二进制基数。
具体表示方法
一个十进制浮点数可以表示为:
\[ \text{value} = \text{sign} \times \text{coefficient} \times 10^{\text{exponent}} \]
例如,数值 123.0678
可以表示为:
\[ 123.0678 = 1 \times 1230678 \times 10^{-4} \]
示例代码
让我们通过代码来展示如何使用 decimal
模块表示和操作十进制浮点数。
from decimal import Decimal, getcontext
# 设置精度(可选)
getcontext().prec = 10
# 创建 Decimal 对象
decimal_value = Decimal('123.0678')
print(f"Decimal value: {decimal_value}")
print(f"Coefficient: {decimal_value.scaleb(0)}") # 系数
print(f"Exponent: {decimal_value.adjusted()}") # 指数
运行上述代码,得到:
Decimal value: 123.0678
Coefficient: 1230678
Exponent: -4