信息的表示和处理
2016-05-10 19:38
281 查看
现代计算机存储和处理的信息以二值信号表示。这些微不足道的二进制数字,或者称为位(bit),奠定了数字革命的基础。孤立的讲,单个的位不是非常有用。然而,当把位组合在一起,再加上某种 解释,即给不同的可能 位模式 赋予含义,我们就能表示任何有限集合的元素。
无符号 编码基于传统的二进制表示法,表示大于等于0的数字。
补码 编码是表示有符号整数的最常见的方式。
浮点数 编码是表示实数的 科学计数法 的以二位基数的版本,所以浮点数不能精确保存,而且由于表示的精度有限,浮点运算是不可结合的。
无符号数采用原码存储,有符号数采用补码存储。正数的补码就是他本身,负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+1. (即在反码的基础上+1)
计算机的表示法是用有限数量的位来对一个数字编码,因此,当结果太大以至不能表示时,某些运算就会导致 溢出。例如,大多数计算机(使用32bit表示整数数据int),计算表达式 200*300*400*500 会得出结果 -884 901 888。
整数的表示虽然只能编码一个相对较小的数值范围,但是这种表示是精确的;而浮点数虽然可以编码一个较大的数值范围,但是这种表示只是近似的。
二进制 -> 十六进制
二进制向十六进制转换时,四位转换成十六进制的一位,运算的顺序是从低位向高位依次进行,高位不足四位用零补。以“1110011”转换成十六进制为例,如下图所示:
转换的结果为:1001011101 == 0X25D
十六进制 -> 二进制
十六进制向二进制转换,就是把十六进制的一位转换成二进制的四位,注意运算的顺序是从低位向高位依次进行。同样以十六进制“0X25D”为例,如下图所示:
如下一段代码:
根据 小端模式 的规定,低字节存储在低地址中,所以对于a = 4 , 低8位将放置在a所占用的4个地址中的最低位。如下:
对于以上代码,如果按照 大端序 存储的话,则如下:
如下两个示例:
当参数
这个函数并不能实现比较两个字符串长度的功能。当s的长度更小时,
转换的原则: 底层的位模式保持不变,改变解释这些位的方式。
将一个无符号数转换为一个更大的数据类型,我们只需要简单地在表示的开头添加0。
符号扩展
将一个有符号数转换为一个更大的数据类型,我们只需要简单地在表示的开头添加符号位。
一、数值的表示
1. 1 数值的编码
数值的类型主要分为2种:整数 和 浮点数。 编码的方式主要分为3种:无符号编码、补码编码 和 浮点数编码。无符号 编码基于传统的二进制表示法,表示大于等于0的数字。
补码 编码是表示有符号整数的最常见的方式。
浮点数 编码是表示实数的 科学计数法 的以二位基数的版本,所以浮点数不能精确保存,而且由于表示的精度有限,浮点运算是不可结合的。
无符号数采用原码存储,有符号数采用补码存储。正数的补码就是他本身,负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+1. (即在反码的基础上+1)
[+1] = [0000 0001]原 = [0000 0001]反 = [0000 0001]补 [-1] = [1000 0001]原 = [1111 1110]反 = [1111 1111]补
计算机的表示法是用有限数量的位来对一个数字编码,因此,当结果太大以至不能表示时,某些运算就会导致 溢出。例如,大多数计算机(使用32bit表示整数数据int),计算表达式 200*300*400*500 会得出结果 -884 901 888。
整数的表示虽然只能编码一个相对较小的数值范围,但是这种表示是精确的;而浮点数虽然可以编码一个较大的数值范围,但是这种表示只是近似的。
1.2 进制转换
编写程序的一个常见任务是在位模式的十进制、二进制、八进制和十六进制表示之间人工进行转换。1.2.1 二进制,八进制 与 十六进制之间的转换
下面以二进制与十六进制之间的转换为例,其他情况在代码中非另外说明:二进制 -> 十六进制
二进制向十六进制转换时,四位转换成十六进制的一位,运算的顺序是从低位向高位依次进行,高位不足四位用零补。以“1110011”转换成十六进制为例,如下图所示:
转换的结果为:1001011101 == 0X25D
// 二进制转换为十六进制 string bin2hex(string two) { string res; // 转换结果 int i = two.length() - 1; // 从最低位开始转换 int j = 0; int sum = 0; // 每4位的和 while (i >= 0) { j = 0; sum = 0; while (j<4 && i >= 0) // 把 “j < 4” 改成 “j < 3” 就变成了“二进制 -> 八进制” { sum += (two[i] - '0') * pow(2, j); // 2^j i--; j++; } if (sum <= 9) res += sum + '0'; else res += sum - 10 + 'A'; } return res; }
十六进制 -> 二进制
十六进制向二进制转换,就是把十六进制的一位转换成二进制的四位,注意运算的顺序是从低位向高位依次进行。同样以十六进制“0X25D”为例,如下图所示:
// 十六进制 -> 二进制 string hex2bin(string hex) { string res; // 转换结果 int i = hex.length() - 1; //从低位开始 int num = 4; //用于保证每个16进制位用4个二进制位来表示 while (i >= 0) { char c = hex[i]; int val; if (c >= '0' && c <= '9') { val = c - '0'; } else if (c >= 'A' && c <= 'F') { val = c - 'A' + 10; } else { return string(); } num = 4; while (val) { res += val % 2 + '0'; val = val / 2; num--; } while (num != 0) //如果转换过程中,已经占用4位,则不用在高位补0 { res += '0'; num--; } i--; } return res; }
1.2.2 十进制转换为任意进制
十进制转换为其他进制较为简单,只要依次取得余数即可。注意,越先出来的余数是越低位。string ten2any(int ten, int rd) // rd : 目标进制 { string res; int val; while (ten) { val = ten % rd; if (val >= 10) res += val - 10 + 'A'; else res += val + '0'; ten = ten / rd; } return res; }
1.2.3 任意进制转换为十进制
二进制数 1010 转换为十进制的过程是: (0 * 2^0) + ( 1 * 2^1) + (0 * 2 ^ 2) + (1 * 2 ^3) = 10。// 任意进制 -> 十进制 int any2ten(string any, int rd) { int i = any.length() - 1; int j = 0; int sum = 0; while (i>=0) { if (any[i] <= '9' && any[i] >= '0') sum += (any[i] - '0') * pow(rd, j); else sum += (any[i] - 'A' + 10) * pow(rd, j); j++; i--; } return sum; }
1.3 大端序 & 小端序
小端序指数据的低字节保存在内存的低地址中,而数据的高字节保存在内存的高地址中 。 大端序刚好相反。如下一段代码:
int a = 4 ; // 0000 0100 int b = 257 ; // 0000 0001 0000 0001
根据 小端模式 的规定,低字节存储在低地址中,所以对于a = 4 , 低8位将放置在a所占用的4个地址中的最低位。如下:
对于以上代码,如果按照 大端序 存储的话,则如下:
1.3.1 判断CPU的?端序
int a = 1; if ((char)a == 1) //取最低地址的一个字节 cout << "小端序" << endl; else cout << "大端序" << endl;
1.3.2 说明
更多关于端序的讨论,可参考 C++ 笔试题集锦(1) - 问题4 。1. 4 无符号数 & 有符号数
有符号数到无符号的隐式强制类型转换经常导致某些非直观的行为。而这些非直观的行为经常导致程序出错。如下两个示例:
float sum_elements(float a[], unsigned len) { int i ; float result = 0; for(i = 0; i <= len - 1; i++) { result += a[i]; } return result; }
当参数
len == 0时,运行这段代码本应该等于0。但是
len - 1 == 4294967295;而且int 的表示范围是 -2147483648~2147483647 , 所以当 i 增长到 2147483647 时,继续+1将变为-2147483648,如此循环下去,所以这个for循环本身就是死循环。另一方面,i 是负数或者太大都会造成a[]数组访问越界。
size_t strlen(const char *s); // 注意 : typedef unsigned int size_t int strlonger(char * s, char * t) { return strlen(s) - strlen(t) > 0; }
这个函数并不能实现比较两个字符串长度的功能。当s的长度更小时,
strlen(s) - strlen(t)将会因为借位得到一个大于0的值。
二、类型转换
当等号两边的类型不一致时,将自动发生隐式类型转换。2.1 相同字长的整数转换
C语言允许无符号数和有符号数之间的转换。转换的原则: 底层的位模式保持不变,改变解释这些位的方式。
char v = -1; // 1111 1111 -> -1 unsigned char uv = v; // 1111 1111 -> 255 char v2 = uv; // 1111 1111 -> -1 unsigned char uc = 0; // 0000 0000 -> 0 uc = uc - 1; // 1111 1111 -> 255 借位,重新解读位模式 char c = 127; // 0111 1111 -> 127 c = c + 1; // 1000 0000 -> -128 进位,重新解读位模式
2.2 不同字长的整数转换
2.2.1 短字长 -> 长字长
零扩展将一个无符号数转换为一个更大的数据类型,我们只需要简单地在表示的开头添加0。
unsigned char -> short unsigned char uc = 128; // 1000 0000 -> 128 short s = uc; // 0000 0000 1000 0000 -> 128 添加0
符号扩展
将一个有符号数转换为一个更大的数据类型,我们只需要简单地在表示的开头添加符号位。
char -> short char uc = -128; // 1000 0000 -> -128 short s = uc; // 1111 1111 1000 0000 -> -128 添加符号位 1 char uc2 = 127; // 0111 1111 -> 127 short s2 = us2; // 0000 0000 0111 1111 -> 127 添加符号位 0
2.2.2 长字长 -> 短字长
当把一个更大数据类型的值 赋给 一个较小数据类型的值时,将发生 截断 。short s = 128; // 0000 0000 1000 0000 -> 128 char c = s; // 1000 0000 -> -128 只获得低8位 short s = 384; // 0000 0001 1000 0000 -> 384 char c = s; // 1000 0000 -> -128 只获得低8位
2.3 说明
更多关于类型转换示例,参考 C++ 类型转换三、整数运算
TODO四、浮点数
TODO相关文章推荐
- iOS开发中页面跳转的方法
- 如何在windows安装Eclipse
- Node.js学习总纲
- Linux驱动开发之 六 (那些必须要了解的硬件知识 之 仪器篇)
- 关于极光推送通知栏无法正确显示应用图标
- NYOJ - 169 素数
- Codeforces 526C - Om Nom and Candies
- JDBC / Spring / MyBatis 性能比较
- 让Myeclipse10支持Mac OSX – Retina显示屏
- COM开发-CComPtr用法
- HDU 3760(最短路思路)
- tr命令
- html 弹窗
- 自定义View----Banner广告条
- css半透明
- Python学习日记.1
- FTP服务
- C++:public继承、protected 继承、private继承
- VM参数收集(部分)
- 使用开源软件的原因