C++ 各种类型取值范围 & 浮点数的二进制表示

Part.I Introduction

首先要说明的一点,不同编译器中相同类型的字节数可能不一样,导致它们们的取值范围不一样。本文主要针对LeetCode,所以内容仅供参考。

Chap.I 预备知识

首先要了解一下下面的知识:

  • 1 位有两种状态:0 或 1
  • 1 字节(byte) = 8 位(bit)
  • 2 7 = 128 2^7=128 27=128 2 8 = 512 2^8=512 28=512 2 16 = 65536 2^{16}=65536 216=65536 2 32 = 4.3 × 1 0 9 2^{32}=4.3\times 10^{9} 232=4.3×109 2 63 = 9 × 1 0 18 2^{63}=9\times 10^{18} 263=9×1018 2 64 = 1.8 × 1 0 19 2^{64}=1.8\times 10^{19} 264=1.8×1019
  • 负数在计算机中的二进制表示方法

Chap.II 小数在计算机中的表示

下图是float的表示方法
在这里插入图片描述
举个例子,我们来表示8.25

  • 整数部分为 8,二进制表示为1000
  • 小数部分为 0.25,小数部分的二进制表示计算方法和整数部分的计算方法恰恰相反,整数部分转换二进制的时候是不断除以 2 得到的,这里就是不断乘以2:0.25*2 = 0.5,整数部分为0,记下:0;0.5*2 = 1.0,整数部分为1,记下:1,所以 0.25 的二进制表示即为 0.011*2^{-2}
  • 于是8.25的(伪)二进制表示为1000.01
  • 根据十进制的科学计数法,二进制的科学计数法可以进行如下类比:1000.01=1.00001*2^3
  • 基于上述,我们便可以直接写出8.25的二进制表示了。因为8.25是正数,所以符号位为0;指数为3(3+127=130),所以1000 0010(130的二进制表示);小数位为00001,因为它有 23 位,后补0,所以0000 1000 0000 0000 0000 000
  • 所以8.25的二进制表示为0 1000 0010 0000 1000 0000 0000 0000 000

检验(暂且不知道如何检验,下面的好像不行):

#include <bitset> 

cout << "8.25的2进制: " << bitset<64>(8.25) << endl;

Part.II 各类型取值范围

变量名 字节数 数据范围
char 1 -128 ~ 127
short 2 -32767 ~ 32768
unsigned short 2 0 ~ 65535
int 4 − 2.1 × 1 0 9 ∼ 2.1 × 1 0 9 -2.1\times 10^{9} \sim 2.1\times 10^{9} 2.1×1092.1×109
unsigned int 4 0 ∼ 4.3 × 1 0 9 0 \sim 4.3\times 10^{9} 04.3×109
long 8 − 9 × 1 0 18 ∼ 9 × 1 0 18 -9\times 10^{18} \sim 9\times 10^{18} 9×10189×1018
unsigned long 8 0 ∼ 1.8 × 1 0 19 0 \sim 1.8\times 10^{19} 01.8×1019
long long 8 − 9 × 1 0 18 ∼ 9 × 1 0 18 -9\times 10^{18} \sim 9\times 10^{18} 9×10189×1018
float 4 ± 3.4 × 1 0 − 38 ∼ ± 3.4 × 1 0 38 ±3.4\times 10^{-38}\sim±3.4\times 10^{38} ±3.4×1038±3.4×1038,1 位符号位,8 位指数位,23 位尾数位;小数点后有效数字 7 位(精度)
double 8 ± 1.7 × 1 0 − 308 ∼ ± 1.7 × 1 0 308 ±1.7\times 10^{-308}\sim±1.7\times 10^{308} ±1.7×10308±1.7×10308,1 位符号位,11 位指数位,52 位小数位;小数点后有效数字 15 位(精度)

#include <climits>#include <float.h> 头文件其实已经用常量记录了不同变量的数据范围。下面是该头文件中的所有符号常量,我们可以通过这些常量查看不同变量的数据范围。

------------------ #include <climits> -------------------------
CHAR_MIN       	char 最小值
SCHAR_MAX      	signed char 最大值
SCHAR_MIN       	signed char 最小值
UCHAR_MAX      	unsigned char 最大值
SHRT_MAX       	short 最大值
SHRT_MIN       	short 最小值
USHRT_MAX      	unsigned short 最大值
INT_MAX       	int 最大值
INT_MIN       	int 最小值
UINT_MAX       	unsigned int 最大值
UINT_MIN        unsigned int 最小值
LONG_MAX      	long 最大值
LONG_MIN       	long 最小值
ULONG_MAX      	unsigned long 最大值
LLONG_MAX      	long long 最大值
LLONG_MIN       long long 最小值
------------------ #include <float.h> -------------------------
FLT_MANT_DIG    	float 类型的尾数
FLT_DIG       	float 类型的最少有效数字位数
FLT_MIN_10_EXP   	带有全部有效数的float类型的负指数的最小值(以10为底)
FLT_MAX_10_EXP    	float 类型的正指数的最大值(以10为底)
FLT_MIN       	保留全部精度的 float 类型正数最小值
FLT_MAX       	float 类型正数最大值
// 还有关于 double 的,就不详细列举了

Part.III 一些技巧

在用 C++ 刷题的时候,很容易因为两个大数相加或相乘导致数据溢出,所以这时候就需要注意了:

  • 隐式类型转换:一个大类型与一个小类型做运算,最后得到一个大类型的数据(除非把它赋值给一个小类型)。比如,一个long与一个int做运算,最后得到一个long,但是如果将结果赋值给一个int,那么赋值的时候会『截位』。
  • 强制类型转换:当两个小类型进行运算的时候,如果运算结果超出了该类型能表示的范围,需用强制类型转换将其转换为大类型。比如,当两个int做乘法运算时,可以用long long ans = (long long)a * b;。后面的a * b不要括号,也就是说先将一个转换为大类型,然后根据隐式类型转换,得到的结果也是大类型,所以就不会溢出了。要括号的话还是会有问题。

Reference

猜你喜欢

转载自blog.csdn.net/Gou_Hailong/article/details/129783477