您的位置:首页 > 其它

C数据类型相关问题

2016-12-05 13:35 288 查看
字节数

char 1

short 2

int 由平台(编译器)决定,可能是2或4,通过sizeof获知

long 由平台(编译器)决定,可能是4或8

float 4

double 8

char*/float* /… x86,4字节,x64,8字节

数据范围

(signed)char (1字节) -128——127

unsigned char 0——255

(signed) short (2字节) -32768——32767

unsigned short 0——65535

(signed ) int (4字节) -2147483648——2147483647

unsigned int 0——4294967295

(signed) long(8字节) -9.223372036854776e+018——9.223372036854776e+018

注:9,223,372,036,854,775,808

unsigend long 0——1.844674407370955e+19

注:18,446,744,073,709,551,615

float -3.4e-38——3.4e+38

double -1.7e-308——1.7e+308

平台无关的整型类型

原因:由于在32位机器和64位机器中,long占据不同的字节数;不同编译器下,int、long都可能占用不同字节数;为了代码的直观

头文件:stdint.h

int8_t

uint8_t

int16_t

uint16_t

int32_t

uint32_t

int64_t

uint64_t

头文件:stddef.h

ssize_t和size_t分别是sign size_t和unsigned signed size of computerwordsize。它们也是表示计算机的字长,在32位机器上是4字节,在64位机器上8字节

浮点数的整数范围

IEEE754 单精度和双精度浮点数,能够精确表示的整数的范围为

Single precision [-2^24, 2^24],等价于10进制的log10(2^24)=7.2数量级

Double precision [-2^53, 2^53],等价于10进制的log10(2^24)=15.9数量级

原理参考

注:受限于浮点数的尾数位,其表示精度是有限的(有效数字),对于很小的小数、或者很大的整数,其精度都会不足。浮点数的精度不是平均分布的呢,和整数的均布不同,浮点数精度是“两头差,中间好”。

为什么对于很小的小数或者很大的整数,会出现精度不足的问题?

这里需要理解浮点数的表示方法以及浮点数的规范化。

浮点数会将实际的数值规范化为科学计数法的表示形式,如121.75,规范化后是1.2175e+2,当然,计算机里要换成二进制的:

(121.75)10 = (1111001.11)2

对二进制数规范化,1111001.11小数点左移6位,然后乘上2的6次方

浮点数分为符号、指数和尾数三部分。

数据类型 符号位 指数位 尾数位

float 31 30~23 22~0

double 63 62~52 51~0

其中,float的指数位是偏移值,相对127偏移的值就是实际的指数值,如,129,指数值为129-127=2,表示2的2次方;同理,double也是偏移值,相对1023偏移。

尾数保存规范化后的小数部分,规范化后的整数部分恒为1,所以不用特意分配一个比特保存这个1。

对于上面的例子,1111001.11在内存中的保存形式如下(假设这是一个float类型):

首先,符号位是0

接着,规范化后的值 1.11100111,小数部分共8位,需要补足至23位,最终的尾数位是11100111000000000000000

最后,规范化的指数值是6,表示为偏移值 127+6=133,转换为二进制10000101,最终的指数位是10000101

所以,1111001.11在内存中保存为0, 10000101, 11100111000000000000000

回到问题本身,由于浮点数的尾数位有限,有效数字是有限的(float是24位,double是53位),如果实际数值的有效数字超过浮点数位数限制,超出的位将会丢失。

例如,11100111000000010001000.11(十进制为7569544.75),其有效数字是25位,如果用float表示,即

float value = 7569544.75;


观察value在内存中的值:

0,10010101,11001110000000100010010

0,011111001,0011001100110011001101

将尾数与原始数比较

11100111000000010001000.11

11001110000000100010010

可以发现,尾数部分刚好是原始数小数点左移22位后将高位”1”省略,并且原始数的小数点后第2位被丢弃了,丢弃的同时进行了舍入,如下所示:

……100011 最后一位舍入变成 ……10010

所以最终的value是等于7569544.0的,此时精确到小数点后1位(这里为0是因为刚才舍入进一了),这种情况就是所谓的“很大的整数”,整数部分的有效数字较多,导致较低位被丢弃。而所谓的“很小的小数”就是指那些无限小数,如0.2,这些无法用二进制精确表示的小数(因为二进制是不断用0.5+0.25+0.125……来逼近原始数的),由于存在尾数舍弃,就会产生精度问题,“很小的小数”就是那些很小的小数位

为什么float能够表示的范围是[-3.4e-38,3.4e+38],而精确表示的范围是[-2^24, 2^24]?

前者指的是float能够表示的最大(最小)整数,但是最大整数与第二最大整数之间的差并不是1,也就是说这两个数之间还存在很多整数float无法表示。

而后者指的就是,在[-2^24, 2^24]内,最大整数与第二最大整数间的差就是1,即2^24=16777216,float能够表示,2^24-1=16777215,float也能够显示。

而对于[-3.4e-38,3.4e+38],这里精确值就不计算了,假设最大值就是 34……56(共39位十进制数),float能够表示,但是34……55,float就不能表示了。

原理跟上面一个问题的是一样的,都是因为浮点数的尾数位有限,有效数字限制了所能表达的整数值,一旦有效数字大于24,多出来的较低位数字就会被舍弃。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C