加载笔记内容...
加载笔记内容...
原码是最直观的数值表示方法,其核心特征是将最高位作为符号位(0表示正,1表示负),其余位表示绝对值。例如8位二进制数:
这种表示方式虽然符合人类直觉,但在计算机运算中存在两个致命缺陷:
反码的改进思路是通过取反操作简化减法运算:
示例(8位):
但反码仍未解决根本问题:
1# 反码加法示例
2def ones_complement_add(a, b, bits=8):
3 max_val = (1 << bits) - 1
4 sum_val = a + b
5 return sum_val if sum_val <= max_val else (sum_val & max_val) + 1
补码通过引入模运算概念,彻底解决了上述问题。其数学基础是:
1负数X的补码 = 模 - |X|
对于n位二进制数,模为2^n。补码特性:
现代计算机普遍采用补码的深层原因:
虽然移码不属于基本数值表示法,但在特定领域至关重要:
移码转换公式:
1E_biased = E + bias (bias = 2^(k-1)-1)
例如32位浮点数的指数偏移值为127
运算符 | 功能说明 | 典型应用场景 |
---|---|---|
& | 按位与 | 掩码操作、奇偶判断 |
| | 按位或 | 标志位设置 |
^ | 按位异或 | 数值交换、加密算法 |
~ | 按位取反 | 补码转换 |
<< | 左移 | 快速乘2^n |
>> | 右移 | 快速除2^n(注意符号扩展) |
快速乘除:
1x << 3 // 等价于 x * 8
2y >> 2 // 等价于 y / 4(对正数有效)
标志位管理:
1#define FLAG_A 0x01
2#define FLAG_B 0x02
3
4int flags = 0;
5flags |= FLAG_A; // 设置标志A
6flags &= ~FLAG_B; // 清除标志B
7if (flags & FLAG_A) { // 检查标志A
8 // 处理逻辑
9}
高效交换(无需临时变量):
1a ^= b
2b ^= a
3a ^= b
符号扩展问题:右移负数时不同语言表现不同
1// Java中使用>>>进行无符号右移
2int x = -8;
3x >> 1; // -4 (带符号)
4x >>> 1; // 2147483644 (无符号)
精度丢失:浮点数位运算需先转整数
1~~12.34 // 12 (双取反截断)
212.34 | 0 // 12 (位或截断)
溢出风险:左移可能超出类型范围
1uint8_t x = 128;
2x << 1; // 0 (溢出)
理解计算机数值表示不仅是掌握编程的基础,更是优化算法、设计高效系统的关键。正如Donald Knuth在《计算机程序设计艺术》中所说:"过早优化是万恶之源,但知其所以然的优化是智慧之源。"