算法与数据结构——基本数据类型与编码

风陵南 / 2024-08-23 / 原文

基本数据类型

基本数据类型是计算机CPU可以直接进行运算的类型,在算法中直接被使用,主要包括以下几种

  • 整数类型byteshortintlong
  • 浮点数类型floatdouble,用于表示小数
  • 字符类型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 。

事实上,计算机内部的硬件电路主要是基于假发运算设计的。这是因为加法运算相对于其他运算(比如乘法除法或减法)来说,硬件实现起来更简单,更容易进行并行化处理,运算速度更快。