基本数据类型
基本数据类型是计算机CPU可以直接进行运算的类型,在算法中直接被使用,主要包括以下几种
- 整数类型
byte
、short
、int
、long
。 - 浮点数类型
float
、double
,用于表示小数 - 字符类型
char
,用于表示各种语言的字母、标点符号甚至表情符号等。 - 布尔类型
bool
,用于表示“是”与“否”判断。
基本数据类型以二进制的形式存储在计算机中。一个二进制位即1比特。在绝大多数现代操作系统中,1字节(byte)由8bite(bit)组成。
基本数据类型的取值范围取决于其占的空间大小,下面以Java为例。
- 整数类型
byte
占用1字节=8比特,可以表示28个数字 - 整数类型
int
占用4字节=32比特,可以表示232个数字
下表列举了各种基本数据类型的占用空间、取值范围和默认值。
类型 | 符号 | 占用空间 | 最小值 | 最大值 | 默认值 |
整数 | byte | 1 字节 | -27(-128) | 27 - 1(127) | 0 |
short | 2 字节 | -215 | 231 - 1 | 0 | |
int | 4 字节 | -231 | 231 - 1 | 0 | |
long | 8字节 | -263 | 263 - 1 | 0 | |
浮点数 | float | 4 字节 | 1.175 * 10-38 | 3.403 * 1038 | 0.0f |
double | 8 字节 | 2.225 * 10-308 | 1.798 * 10-308 | 0.0 | |
字符 | char | 2 字节 | 0 | 216-1 | 0 |
布尔 | bool | 1 字节 | false | true | false |
字符char的大小在C和C++中为1字节。
基本数据类型提供了数据的“内容类型”,而数据结构提供了数据的“组织方式”。
数字编码
在前面的取值范围中,所有整数类型能够表示的负数都比正数多一个,例如bute的取值范围是[-128,127]。其原因涉及原码、反码、补码的相关知识。
- 原码:我们将数字的二进制表示的最高位视为符号位,其中0表示正数,1表示负数,其余位表示数字的值。
- 反码:正数的反码与其原码相同,负数的反码是对其原码除符号位外的所有位取反。
- 补码:正数的补码与其原码相同,负数的补码是在其反码的基础上加1。
注意:数字是以“补码”的形式存储在计算机中的。
原码(sign-magnitude)虽然最直观,但存在一些局限性。一方面,负数的原码不能直接用于运算。例如在原码下计算 1 + ( - 2),得到的结果是 - 3,这显然是不对的。
为解决此问题,计算机引入了反码。如果我们先将原码转换为反码,并在反码下计算 1 + (- 2),最后将结果从反码转换回原码,则可得到正确结果 -1。
另一方面,数字零的原码有 +0 和 -0 两种表示方式。这意味着数字零对应两个不同进制的二进制编码,这可能会带来歧义。与原码一样,反码也存在正负零歧义问题,因此计算机进一步引入了补码。下面是负零的原码、反码、补码的转换过程。
在负零的反码基础上加1会产生进位,但byte类型的长度只有8位,因此溢出到第9位的1会被舍去,这样,负零的补码为 0000 0000,与正零的补码相同。这意味着在补码表示中只存在一个零,正负从而得到解决。
注意:byte类型的取值范围是[-128, 127],多出来的一个负数-128是如何得到的?
我们注意到,区间[-127, +127]内的所有整数都有对应的原码、反码和补码,并且原码和补码之间可以互相转换。
然而,补码1000 0000 是一个例外,它并没有对应的原码。根据转换方法,我们得到该补码的原码为 0000 0000。这显然是矛盾的,因为该原码表示数字0,它的补码应该是自身。计算机规定这个特殊的补码1000 0000 就代表 -128。实际上(-1)+(-27)在补码下的计算结果就是 -128 。
事实上,计算机内部的硬件电路主要是基于假发运算设计的。这是因为加法运算相对于其他运算(比如乘法除法或减法)来说,硬件实现起来更简单,更容易进行并行化处理,运算速度更快。