> 文章列表 > C++ 各种类型取值范围 浮点数的二进制表示

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

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

文章目录

  • Part.I Introduction
    • Chap.I 预备知识
    • Chap.II 小数在计算机中的表示
  • Part.II 各类型取值范围
  • Part.III 一些技巧
  • Reference

Part.I Introduction

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

Chap.I 预备知识

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

  • 1 位有两种状态:0 或 1
  • 1 字节(byte) = 8 位(bit)
  • 27=1282^7=12827=12828=5122^8=51228=512216=655362^{16}=65536216=65536232=4.3×1092^{32}=4.3\\times 10^{9}232=4.3×109263=9×10182^{63}=9\\times 10^{18}263=9×1018264=1.8×10192^{64}=1.8\\times 10^{19}264=1.8×1019
  • 负数在计算机中的二进制表示方法

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

下图是float的表示方法
C++ 各种类型取值范围  浮点数的二进制表示
举个例子,我们来表示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×109∼2.1×109-2.1\\times 10^{9} \\sim 2.1\\times 10^{9}2.1×1092.1×109
unsigned int 4 0∼4.3×1090 \\sim 4.3\\times 10^{9}04.3×109
long 8 −9×1018∼9×1018-9\\times 10^{18} \\sim 9\\times 10^{18}9×10189×1018
unsigned long 8 0∼1.8×10190 \\sim 1.8\\times 10^{19}01.8×1019
long long 8 −9×1018∼9×1018-9\\times 10^{18} \\sim 9\\times 10^{18}9×10189×1018
float 4 ±3.4×10−38∼±3.4×1038±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×10−308∼±1.7×10308±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

  • C/C++ 各种变量的数据范围
  • C++十进制转二进制(含小数部分)