C语言中的正负数及其输出
在数学中,数字有正负之分。在C语言中也是一样,short、int、long 都可以带上正负号,例如:
/负数
short a1 = -10;
short a2 = -0x2dc9; //十六进制
//正数
int b1 = +10;
int b2 = +0174; //八进制
int b3 = 22910;
//负数和正数相加
long c = (-9) + (+12);
如果不带正负号,默认就是正数。
符号也是数字的一部分,也要在内存中体现出来。
符号只有正负两种情况,用1位(Bit)就足以表示;C语言规定,把内存的最高位作为符号位。以 int 为例,它占用 32 位的内存,0~30 位表示数值,31 位表示正负号。如下图所示:
注·这里的31就是第32位,0就是第一位。
C语言规定,在符号位中,用 0 表示正数,用 1 表示负数。例如 int 类型的 -10 和 +16 在内存中的表示如下:
short、int 和 long 类型默认都是带符号位的,符号位以外的内存才是数值位。如果只考虑正数,那么各种类型能表示的数值范围(取值范围)就比原来小了一半。
- 打个比方,1字节(Byte)由8个位(bit)组成。那么他最大就可以表示255。假如第一位变成了0,那他最大就只能表127。
但是在很多情况下,我们非常确定某个数字只能是正数,比如班级学生的人数、字符串的长度、内存地址等,这个时候符号位就是多余的了,就不如删掉符号位,把所有的位都用来存储数值,这样能表示的数值范围更大(大一倍)。
C语言允许我们这样做,如果不希望设置符号位,可以在数据类型前面加上 unsigned 关键字,例如:
unsigned short a = 12;
unsigned int b = 1002;
unsigned long c = 9892320;
如果是unsigned int类型,那么可以省略 int ,只写 unsigned。
整数在内存中是如何存储的
在计算机中,有符号数在存储和读取时都要进行转化。
源码
将一个整数转换成二进制形式,就是其原码。
例如short a = 6;a的原码就是----- 0000 0000 0000 0110;
更改a的值a = -18,此时a的原码就是--1000 0000 0001 0010。
反码
谈到反码,需要将正数和负数区别对待,因为它们的反码不一样。
对于正数,它的反码就是其原码(原码和反码相同)。
负数的反码就是将原码中除符号位以外的所有位(数值位)取反。
也就是0变成1,1变成0。
例如short a = 6,a的原码和反码都是0000 0000 0000 0110
更改a的值a = -18,此时a的反码是 1111 1111 1110 1101
补码
对于正数,它的补码就是其原码(原码、反码、补码都相同)。
负数的补码是其反码加 1
例如:
short a = 6
;a 的原码、反码、补码都是0000 0000 0000 0110;
更改 a 的值a = -18;,此时 a 的补码是1111 1111 1110 1110。
原码、反码、补码的概念只对负数有实际意义,对于正数,它们都一样。最后我们总结一下 6 和 -18 从原码到补码的转换过程:
- 注:在计算机内存中,整数一律采用补码的形式来存储。这意味着,当读取整数时还要采用逆向的转换,也就是将补码转换为原码。
将补码转换为原码也很简单:先减去 1,再将数值位取反即可。C语言中的小数
C语言中小数的指数形式为:
aEn 或 aen
a 为尾数部分,是一个十进制数;n 为指数部分,是一个十进制整数;E或e是固定的字符,用于分割尾数部分和指数部分。
整个表达式等价于 a×10n。
指数形式的小数举例: - 2.1E5 = 2.1×105,其中 2.1 是尾数,5 是指数。
- 3.7E-2 = 3.7×10-2,其中 3.7 是尾数,-2 是指数。
- 0.5E7 = 0.5×107,其中 0.5 是尾数,7 是指数。
C语言中常用的小数有两种类型,分别是 float 或 double;
float 称为单精度浮点型,double 称为双精度浮点型。
- 注:float 始终占用4个字节,double 始终占用8个字节。
小数输出形式
小数也可以使用 printf 函数输出,包括十进制形式和指数形式,它们对应的格式控制符分别是:
- %f 以十进制形式输出 float 类型;
- %lf 以十进制形式输出 double 类型;
- %e 以指数形式输出 float 类型,输出结果中的 e 小写;
- %E 以指数形式输出 float 类型,输出结果中的 E 大写;
- %le 以指数形式输出 double 类型,输出结果中的 e 小写;
-
%lE 以指数形式输出 double 类型,输出结果中的 E 大写。
#include <stdio.h> #include <stdlib.h> int main() { float a = 0.302; float b = 128.101; double c = 123; float d = 112.64E3; double e = 0.7623e-2; float f = 1.23002398; printf("a=%e \n b=%f \n c=%lf \n d=%lE \n e=%lf \n f=%f\n", a, b, c, d, e, f); return 0; }
----------->结果如下:
注意: - %f 和 %lf 默认保留六位小数,不足六位以 0 补齐,超过六位按四舍五入截断。
- 将整数赋值给 float 变量时会变成小数。
- 以指数形式输出小数时,输出结果为科学计数法;也就是说,尾数部分的取值为:0 ≤ 尾数 < 10。
%g
%g 会对比小数的十进制形式和指数形式,以最短的方式来输出小数,让输出结果更加简练。所谓最短,就是输出结果占用最少的字符。
#include <stdio.h>
#include <stdlib.h>
int main()
{
float a = 0.00001;
float b = 30000000;
float c = 12.84;
float d = 1.229338455;
printf("a=%g \nb=%g \nc=%g \nd=%g\n", a, b, c, d);
return 0;
}
///运行结果:
a=1e-05
b=3e+07
c=12.84
d=1.22934
注:
- %g 默认最多保留六位有效数字,包括整数部分和小数部分;%f 和 %e 默认保留六位小数,只包括小数部分。
- %g 不会在最后强加 0 来凑够有效数字的位数,而 %f 和 %e 会在最后强加 0 来凑够小数部分的位数。
- %g 和 %lg 分别用来输出 float 类型和 double 类型,并且当以指数形式输出时,e小写。
- %G 和 %lG 也分别用来输出 float 类型和 double 类型,只是当以指数形式输出时,E大写。
Thanks for share!