⌨️ 第三章 数值和数据的处理方法
📄 一句话概括

不同类型的数字要一起运算就得【换户口】:自动转换由编译器悄悄办(小类型升大类型,安全)、强制转换是你亲手办(可能截断丢数据);而溢出是换不过来的【爆仓】——21 亿加 1 变成负 21 亿是本节的招牌事故。

📝 本节和前面几节的关系

3-7 讲了整数与浮点两大阵营的范围,这一篇讲【跨越阵营时发生什么】。溢出是 3-7 【范围封顶】的直接后果,也是 C++ 课 2.4.1 类型系统的另一面。

一、自动转换(隐式):编译器只办【升级】

运算里两种类型相遇时,编译器自动把【小】的转成【大】的——升级规则:整数比字节数,浮点压过整数:

int + float  ->  float     (int 升级为 float 再算)
int8 + int32 ->  int32
print(3 + 0.5)    # 3.5 —— Python 自动把 3 升级为浮点
print(True + 1)   # 2    —— True 被当 1(布尔是整数的特例)

为什么只【升】不【降】:int 转 float 可能丢精度、float 转 int 要丢小数——自动转换只做不丢信息的那一档,其余要你亲自动手并负责。

二、强制转换(显式):你签字,你负责

print(int(3.7))        # 3    —— 直接砍掉小数(不是四舍五入!)
print(int(3.2))        # 3
print(float(3))        # 3.0
print(str(255))        # "255" —— 数字变字符串
print(int("255"))      # 255  —— 字符串变数字(回收树莓派课 6-3:input() 永远返回字符串,接数值必须转)

int() 截断方向要记牢:int(3.7) 得 3、int(-3.7) 得 -3——一律朝零砍,不是四舍五入(四舍五入要用 round)。

三、溢出:盒子装不下的爆仓瞬间

整数类型范围封顶(3-7 的表),超出就是溢出。C 家族的行为:

int32 最大 2147483647(2^31 - 1)+ 1 -> -2147483648

加 1 反而变最大负数——二进制只有 31 位表示大小,装满后进位【卷】进了符号位。这类事故史上最著名的案例:盖姆丽游戏《文明》里的甘地(好战值 255 再减,卷回极端好战)、YouTube 点赞数破 2^31(2014 年后必须换 int64)。

两大流派的对策:

流派 行为 代表
不设防 静默溢出(卷符号位)——快,但埋雷 C/C++(有符号溢出是未定义行为)/Java(静默卷回)
防爆仓 越界直接抛异常/自动扩容 Python(int 无限精度)、C# 开启 checked 时

四、动手 Demo:三幕剧

print(int(3.9), int(-3.9))            # 3 -3    朝零截断
print(2 ** 31 - 1)                    # 2147483647  int32 的天花板
print(2147483647 + 1)                 # 2147483648  Python:不溢出,老实变大
print(1e308 * 10)                     # inf     浮点上溢:表示不下了,给无穷

看到什么算成功:3 -3、2147483647、2147483648、inf。

读结果:Python 的 int 没有天花板(2147483648 老实写出来),同样的代码在 C/Java 里会卷成 -2147483648——语言不同、后果不同;浮点倒是会溢出,但方式体面(变成 inf 无穷大)。写 Python 时别丢了敬畏:对接的数据库、文件格式、硬件寄存器全是定长整数,Python 帮你算对了,存进去照样可能溢。

五、30 秒实验

跑 int("3.7")——报 ValueError!int() 转字符串时只认纯整数字符串(int("3") 才行),带小数点的要先 float("3.7") 再取整。字符串转数和数转数是两条不同的路,30 秒记牢。

六、常见误区

  1. 【自动转换很聪明,什么都能自动】——错。它只办【升档】(不丢信息)的;float 转 int、长字符串转数字都必须显式做——这是设计而不是限制。
  2. 【int(3.7) 是四舍五入】——错。朝零截断得 3;四舍五入是 round(3.7) 得 4。两者差 1,账目对不上多半栽在这。
  3. 【Python 整数无限精度,所以永远不用管溢出】——错。Python 之外的世界全是定长整数:数据库列类型、C 扩展、网络协议、文件格式——出了 Python 边界,爆仓照旧。
自测三问(点开对答案) 1. **为什么自动转换只【升】不【降】?** 答:升级(小类型转大类型)不丢信息,编译器能替你保证正确;降级会截断丢数据,必须显式声明由程序员负责。 2. **int32 的 2147483647 加 1 在 C/Java 里结果是什么?为什么?** 答:-2147483648——31 位数值位装满,进位卷进符号位(Python 里则是诚实的 2147483648,因为 int 不封顶)。 3. **int("3.7") 为什么报错?** 答:int() 对字符串只接受纯整数写法;带小数点要先 float() 转换再取整——字符串转换与数值转换是两条路。

相关笔记