计算机编程中的数据类型

一. 整型(int/unsigned int

1. 机器数

  • 原码:由符号位(正数为0,负数为1)和真值绝对值(二进制)表示。

    表示范围为 2 n 1 + 1 0 -2^{n-1}+1\sim 0 + 0 + 2 n 1 +0\sim +2^{n-1}

    例如,以8 bit字长为例(下同), [ 74 ] = 1100   1010 [-74]_原 = 1100\ 1010

    注意, [ + 0 ] = 0000   0000 [ 0 ] = 1000   0000 [+0]_原=0000\ 0000 \ne [-0]_原=1000\ 0000

  • 反码:正数的反码与其原码相同;对于负数,其原码的符号位不变,数值位按位求反。

    表示范围为 2 n 1 + 1 0 -2^{n-1}+1\sim 0 + 0 + 2 n 1 +0\sim +2^{n-1}
    例如, [ 74 ] = 1011   0101 [-74]_反 = 1011\ 0101
    注意, [ + 0 ] = 0000   0000 [ 0 ] = 1111   1111 [+0]_反=0000\ 0000 \ne [-0]_反=1111\ 1111

  • 补码:正数的补码与其原码相同;负数的补码有两种计算方法:

    • 方法一:负数的补码是其反码+1的结果,若有溢出,则舍弃溢出位。例如, [ 74 ] = 1011   0101 + 1 = 1011   0110 [-74]_补 = 1011\ 0101+1 = 1011\ 0110
    • 方法二:负数 x x 的补码 [ x ] = 2 n x [x]_补 = 2^n-|x| 。例如, [ 74 ] = 2 8 74 = 1011   0110 [-74]_补 = 2^8-74 = 1011\ 0110

    表示范围为 2 n 1 + 2 n 1 1 -2^{n-1}\sim + 2^{n-1}-1

    另外, [ + 0 ] = [ 0 ] = 0000   0000 [+0]_补= [-0]_补=0000\ 0000 [ ( x ) ] = x \left[ (x)_补 \right]_补 = x

  • 移码:由补码的符号位取反得到,即: [ x ] = 2 n 1 + x [x]_补 = 2^{n-1}+x (其中 2 n x < 2 n -2^n\le x< 2^n )。例如 [ 74 ] = 2 7 74 = 0011   0110 [-74]_移 = 2^7-74 = 0011\ 0110
    另外, [ + 0 ] = [ 0 ] = 1000   0000 [+0]_移 = [-0]_移 = 1000\ 0000

2. 整型数的表示方法

  • 有符号整型数(int)的表示方法:在内存中以补码的形式存储(long/short等与之类似)。

  • 无符号整型数(unsigned int)的表示方法:在内存中以无符号数的形式存储。

3. 整型数的计算

(1) 类型转换

intint,或unsigned intunsigned int之间进行运算,结果的类型不变;intunsigned int之间进行运算,结果为unsigned int,如下面代码中:

#include <iostream>
using namespace std;

int main()
{
    int a = -2;
    unsigned int b = 1;
    cout << a + b << endl;
}

输出结果不为-1,而为4294967295(二进制的4个字节全为1),即说明-2在内存是以补码存储的(补码为1000 … 0010),与无符号的1(二进制0000 … 0001)相加,结果为1111 … 1111。

此外需要注意,若两个操作数均为int型,则结果一定为int型(如18*5/9结果为10)。

(2) 移位运算

左移1位可以实现×2操作,右移1位可以实现÷2操作。

进行移位运算时,符号位不变,只有数值位参与移位。若为正数,则左移(或右移)时,最高位(最低位)舍弃,最低位(最高位)空出,填补0;若为负数,则左移时空缺位填补0,右移时空缺位填补1。

例如:-10的补码为1111 0110,左移1位得1110 1100,真值为-20。

(3) 有关溢出

unsigned int型(32位)为例,其最大值为0xFFFFFFFF(可通过printf("%x",UINT_MAX);查得),若产生溢出,则系统默认对 2 32 2^{32} 取余。如:

unsigned int ui = 0xFFFFFFFF;
ui += 2;
cout << ui << endl;

结果为1。

二. 浮点型(float/double

1. 浮点数的表示方法

(1) 一般表示形式

N = S × r j N = S\times r^j ,其中 S S 为尾数(小数,可正可负,且 S 1 |S|\le 1 ), r r 为尾数的基值(一般取2、8、16等), j j 为阶码(二进制整数)。

例如:
N = 11.0101 = 1.10101 × 2 1 = 0.110101 × 2 10 = 0.00110101 × 2 100 \begin{aligned} N &=11.0101 \\ &=1.10101×2^1\\ &=0.110101×2^{10} \\ &=0.00110101×2^{100} \end{aligned}

(2) 规格化

1 2 S < 1 \frac 1 2 \le |S| < 1 时, S S 为规格化数。

规格化形式( S > 0 S>0 规格化形式( S < 0 S<0 特点
真值 0.1 × × 0.1 \times \times \cdots 0.1 × × -0.1 \times \times \cdots
原码 0.1 × × 0.1 \times \times \cdots 1.1 × × 1.1 \times \times \cdots
补码 0.1 × × 0.1 \times \times \cdots 1.0 × × 1.0 \times \times \cdots 数符和第一位不同

0.110101 × 2 10 0.110101×2^{10} 符合规格化标准。

(3) IEEE754标准

在IEEE754标准中,float型浮点数的表示方式为(32位):

符号位 S S 阶码 N N 尾数 M M
31(1位) 30~23(8位) 22 ~ 0(23位)

其中:

  • 符号位 S S ——0表示正数,1表示负数;

  • 阶码 N N ——用移码表示,偏移量为127;

  • 尾数 M M ——有效数字位(补码),由于 M M 符合规格化标准,故整数部分的无需进行存储。

例如-125.5,符号位 S = 1 S=1 ;其绝对值二进制表示为 1111101.1 = 1.111101 × 2 6 1111101.1=1.111101×2^6 (这里6为十进制),故尾数 M = 111101 M=111101 (舍去了整数部分1),补全23位得111 1011 0000 0000 0000 0000;阶码 N = 6 + 127 = 133 N=6+127=133 ,即1000 0101。
故-125.5在内存中表示为:1 10000101 11110110000000000000000。
通过以下程序可以得到验证:

#include <iostream>
using namespace std;

int main()
{
    float a = -125.5;
    char *p = (char *)&a;
    printf("%d ",*p);		// 输出结果:0
    printf("%d ",*(p+1));	// 输出结果:0
    printf("%d ",*(p+2));	// 输出结果:-5
    printf("%d ",*(p+3));	// 输出结果:-62
}

也可以在debug模式中,在内存中输入地址&a,查得存储的内容为(由低字节到高字节)00 00 FB C2,即C2FB0000,从而得证。

double型浮点数表示方式完全类似,只是变为64位,且阶码的偏移量变为1023:

符号位 S S 阶码 N N 尾数 M M
63(1位) 62~52(11位) 51 ~ 0(52位)

(4) 浮点数的表示范围

浮点数的表示范围

设尾数有 n n 位,阶码有 m m 位,则:

  • 最小负数: ( 1 2 n ) × 2 ( 2 m 1 ) -(1-2^{-n} )×2^{(2^m-1)}
  • 最大负数: 2 n × 2 ( 2 m 1 ) -2^{-n}×2^{-(2^m-1)}
  • 最小正数: 2 n × 2 ( 2 m 1 ) 2^{-n}×2^{-(2^m-1)}
  • 最大正数: ( 1 2 n ) × 2 ( 2 m 1 ) (1-2^{-n} )×2^{(2^m-1)}

小于最小负数和大于最大正数的范围,称为上溢区,此区域的浮点数视为溢出;在最大负数和最小正数之间的区域,称为下溢区,此区域的浮点数视为0。

2. 浮点数的计算

(1) 类型转换

浮点数运算时,两个操作数中只要有一个为浮点型(不论为float型还是double型),都转化为double型进行运算,结果也为double型。

(2) 浮点数加减运算

设两个浮点数 x = S x 2 j x x=S_x⋅2^{j_x} y = S y 2 j y y=S_y⋅2^{j_y} ,计算 x ± y x±y 的步骤如下:

  • 对阶:若阶差 Δ j = j x j y = 0 Δj=j_x-j_y=0 ,则表明已经对齐;若不为0,则需要“小阶向大阶看齐”(以防止移位时最高位丢失):将小阶 + Δ j +Δj 补至大阶,尾数右移 Δ j Δj 位;

  • 尾数相加;

  • 规格化:例如, [ x + y ] [x+y]_补 的阶码为11,尾数为11.1001,则将尾数左规,变为1.0010,阶码降为10;当尾数出现 01. × × 01.××… 10. × × 10.××… 时,表示出现了溢出,应右规,阶码+1;

  • 舍入:0舍1入法或末尾恒置1法;

  • 溢出判断:见浮点数的表示范围。

(3) 浮点数的乘除运算

乘(除)运算只需要将尾数相乘(除),阶码相加(减)即可。

三. 字符型(char

1. 表示方法

在内存中,字符以ASCII码对应的整型数存储(8位)。

2. 计算方法

在计算时,不论char还是unsigned char型,均转换为int型进行计算。

发布了1 篇原创文章 · 获赞 0 · 访问量 97

猜你喜欢

转载自blog.csdn.net/szzheng/article/details/104339315