整型 Integer Number
变量的初始化
#include <iostream>
using namespace std;
int main()
{
int num1, num2;
cout << "num1 = " << num1 << endl;
cout << "num2 = " << num2 << endl;
}
这里定义了两个整型变量num1
、num2
,没有对其进行初始化就直接输出。但编译器并不会报错,因为没有语法错误。
程序的输出结果与编译器有关,比如x86平台的输出为
num1 = 4354254
num2 = 7208832
而ARM平台的结果为
num1 = 0
num2 = 0
对于Java语言,如果不初始化直接编译,编译器就会报错。
不同的初始化方式
int num = 10;
// New Standard
int num (10);
int num {10};
溢出 Overflow
#include <iostream>
using namespace std;
int main()
{
int a = 56789;
int b = 56789;
int c = a * b;
cout << c << endl;
}
正确结果应该为3,224,990,521,但程序输出为-1069976775。
3,224,990,521对应16进制为0xC0397339,一共32位,最高位C大于8,那么对应二进制的最高位就是1。而对于int
类型,其32位的最高位代表符号位(sign bit),若符号位为1,则代表这个变量是负数。要输出正确结果,可将int
改为unsigned int
。
int
的范围:
[
−
2
31
,
2
31
−
1
]
[-2^{31},2^{31}-1]
[−231,231−1]。
unsigned int
的范围:
[
0
,
2
32
−
1
]
[0,2^{32}-1]
[0,232−1]。
数据类型所占字节数
一般来说,int
类型占4个字节,即32位(有少部分系统是16位)。
对于short
类型,最低要求是2个字节(16位);对于long
类型,最低要求是4个字节(32位);对于long long
类型,最低要求是8个字节(64位)。C++语言没有强制规定这些类型必须占多少字节,有可能long
类型和int
类型均为4个字节,需要具体验证。
查看某一类型在当前系统所占的字节数:
cout << "sizeof(int) = " << sizeof(int) << endl;
cout << "sizeof(short) = " << sizeof(short) << endl;
cout << "sizeof(long) = " << sizeof(long) << endl;
字符型 Char
实际上是一个8位整数,可以用signed
和unsigned
修饰,但不同的平台是不一样的,C++没有具体规定。
char c1 = 'C';
char c2 = 80;
char c3 = 0x50;
// Chinese Character
char16_t c4 = u'啊'; // C++11
char32_t c5 = U'啊'; // C++11
char16_t
和char32_t
分别表示16位和32位的char
。前面的u和U表示把后面的字符转换成对应的数据类型。
使用下面的语句打印结果:
cout << c1 << ":" << c2 << ":" << c3 << endl;
cout << +c1 << ":" << +c2 << ":" << +c3 << endl;
cout << c4 << endl;
cout << c5 << endl;
输出结果:
C:P:P
67:80:80
21834
21834
第一行为打印c1
、c2
和c3
对应的字符,如果想要打印字符对应的整数,可以在前面加一个+
,将其强制转换为整型。
布尔类型 bool
在C++中是一种数据类型,占1个字节(8位),但在C语言中不是一种数据类型。
只有两种取值true(1)
、false(0)
,可以当做具体的数值来计算。
与bool类型相关的类型转换
int a;
bool b = true;
a = b;
bool c = -123;
● 将b
赋值给a
,a
的值为1。
● 将任意数赋值给bool
类型的变量,只要这个数不是0,bool
类型的变量就是1。
浮点数类型
double
为双精度,long double
为扩展精度(64位or128位)。
深度学习中涉及半精度(half precision),不是C++的标准。
浮点数的精度
执行以下代码
#include <iomanip>
using namespace std;
int main()
{
float f1 = 1.2f;
float f2 = f1 * 1000000000000000;
cout << std::fixed << std::setprecision(15) << f1 << endl;
cout << std::fixed << std::setprecision(15) << f2 << endl;
return 0;
}
输出结果为
1.200000047683716
1200000038076416.000000000000000
可以看到,f1
的输出并不是1.2,f2
的输出也和正确的结果有一定的差距,这与浮点数的表示方法有关,可以参考PAM信号里的量化来理解。
让一个极大的数(1.23E10+f)和一个极小的数(123)相加,如果这个极小的数没有超过量化间隔,那么结果仍然还是1.23E10。
在实际应用中,判断两个浮点数相等,通常采取下面的方式:
if (f1 == f2) //bad
{
// ...
}
if (fabs(f1 - f2) < FLT_EPSILON) // good
{
// ...
}
fabs()
为绝对值,FLT_EPSILON
是float
类型所能识别的最小精度。
auto类型
是一种自动的类型,根据赋值来确定变量类型。
auto a = 2; // type of a is int
auto b = 2.3; // type of b is double
auto c; // valid in C, error in C++
auto d = a * 1.2;
对于C++,使用auto
初始化一个变量,必须赋值。而在赋值之后,变量的类型就被确定下来,不会发生改变。
auto a = 2;
a = 2.3;
这里a
仍然是2,程序会将2.3的小数部分截去,只留下整数部分,赋值给a
。
类型转换
int num_int1 = 'C';
int num_int2 = (int)'C'; // C style
int num_int3 = int('C'); // C++ style
上面三行都是类型转换。第一行属于隐式转换,后两种属于显式转换。其中,第二行为C语言的写法,第三行为C++的写法。
int num_int4 = 2.8;
float num_int5 = 2.3;
short num_int6 = 10000000;
第一行,属于double
型转换为int
型,直接截去小数部分,把整数部分赋给num_int4
。
第二行,属于double
类型转换为float
类型,可能会损失精度。
第三行,10000000已经超过了short
类型所能表示的最大值,编译器会发出warning