### 2.2.3 浮点数类型 float
浮点数就是包含小数点的数,大体对应于数学中的实数集合。现实世界中的职工工资(以 元为单位)、房屋面积(以平方米为单位)、人的身高(以米为单位)、圆周率等在程序中都 适合用浮点数表示。
Python 语言提供了类型 float 用于表示浮点数。float 类型的字面值形式与数学中的 写法基本一致,但是允许小数点后面没有任何数字(表示小数部分为 0),例如下列字面值 都是浮点数:
```
3.1415 -6.78 123.0 0\. -6.
```
Python 为浮点数类型提供了通常的加减乘除等运算,运算符与整数类型是一样的(见 表 2.1)。但是,与整数类型不同的是,运算符“/”用于浮点数时,是要保留小数部分的, 例如:
```
>>> 11.0 / 3.0
3.6666666666666665
```
没错,最后一位小数是 5 而不是 6!原因见下面关于浮点数内部表示的内容。 将一个浮点数赋值给变量,则该变量就是 float 类型(实际上是指向一个 float 类型的数据)。例如:
```
>>> f = 3.14
>>> type(f)
<type 'float'>
```
浮点数运算同样可以和变量赋值结合起来,形成如表 2.2 所示的简写形式。
浮点数的能力与限制 浮点数类型能够表示巨大的数值,能够进行高精度的计算。但是,由于浮点数在计算机
内是用固定长度的二进制表示的,有些数可能无法精确地表示,只能存储带有微小误差的近 似值。例如,
```
>>> 1.2 – 1.0
0.19999999999999996
```
结果比 0.2 略小。又如:
```
>>> 2.2 – 1.2
1.0000000000000002
```
结果比 1.0 略大。然而,下面这个表达式却计算出了精确结果:
```
>>> 2.0 – 1.0
1.0
```
尽管浮点表示带来的这种微小误差不至于影响数值计算实际应用,但在程序设计中仍然 可能导致错误。例如,万一某个程序中需要比较 2.2 ? 1 是否等于 1.2,那我们就得不到 预期的肯定回答,因为 Python 的计算结果是不相等!请看下面两个比较式:
```
>>> (1.2 – 1.0) == 0.2
False
>>> (2.0 – 1.0) == 1.0
True
```
先解释一下,上例中用到了比较两个表达式是否相等的运算符“==”,另外显示结果出 现了表示真假的布尔值 True 和 False,这些内容在后面布尔类型一节中有详细介绍。从 这个例子我们得到一条重要的经验:不要对浮点数使用==来判断是否相等。正确的做法是 检查两个浮点数的差是否足够小,是则认为相等。例如:
```
>>> epsilon = 0.0000000000001
>>> abs((1.2 – 1.0) - 0.2) < epsilon
True
```
另外从运算效率考虑,与整数类型 int 相比,浮点数类型 float 的运算效率较低,由 此我们得出另一条经验:如果不是必须用到小数,那就应当使用整数类型。
科学记数法
对于很大或很小的浮点数,Python 会自动以科学记数法来表示。所谓科学记数法就是
以“a×10 的整数次幂”的形式来表示数值,其中 1 <= abs(a) < 10。例如,12345 可 以表示成 1.2345e+4,0.00123 可以表示为 1.2345e-3。下面是 Python 的计算例子:
```
>>> 1234.5678 ** 9
6.662458388479362e+27
>>> 1234.5678 ** -9
1.5009474606688535e-28
```
正如 int 不同于整数集 I 一样,Python 的 float 也不同于实数集 R,因为 float 仍 然只能表示有限的浮点数。当一个表达式的结果超出了浮点数表示范围的时候,Python 会 显示结果为 inf(无穷大)或-inf(负无穷)。读者可以做一个有趣但略显麻烦的实验,试 一试 Python 最大能表示多大的浮点数。下面是本书著者所做的实验结果,可以看到,最大 浮点数的数量级是 10308,有效数字部分已经精确到小数点后面第 53 位(Python 在显示结果 时只保留小数点后 16 位),当该位为 6 时是合法的浮点数,当该位为 7 时则超出范围。
```
>>> 1.79769313486231580793728971405303415079934132710037826e+308
1.7976931348623157e+308
>>> 1.79769313486231580793728971405303415079934132710037827e+308
inf
```
顺便说一下,如果读者做这个实验,相信你一定会采用一种快速有效的策略来确定每一 位有效数字,而不会对每一位都从 0 试到 9。例如,当发现 1.7…1e+308 是合法的浮点数, 而 1.7…9e+308 超出了范围,接下去应当检查 1.7…5e+308 的合法性。这种方法就是本 书后面算法设计一章中介绍的二分查找策略。我们在第 1 章说过,计算思维人人皆有、处处 可见,不是吗?
自动类型转换
float 类型与 float 类型的数据相互运算,结果当然是 float 类型。问题是 float 类型能与 int 或 long 类型进行运算吗?
由于整数、长整数和浮点数都是数值(在数学上都属于实数集合 R),因此 Python 允许
它们混合运算,就像 int 可以与 long 混合运算一样。Python 在对混合类型的表达式进行 求值时,首先将 int 或 long 类型转换成 float,然后再执行 float 运算,结果为 float 类型。例如:
```
>>> type(2 + 3.0)
<type 'float'>
>>> type(2 + 3L * 4.5)
<type 'float'>
```
手动类型转换
除了在计算混合类型的表达式时 Python 自动进行类型转换之外,有时我们还需要自己 手动转换类型。这是通过几个类型函数 int()、long()和 float()实现的。例如,当我 们要计算一批整型数据的平均值,程序中一般会先求出这批数据的总和 sum,然后再除以数 据的个数 n,即:
```
average = sum / n
```
但这个结果未必如我们所愿,因为 sum 和 n 都是整数,Python 执行的是整数除法,小数部 分被舍弃了,导致结果误差太大。为解决此问题,我们需要手动转换数据类型:
```
average = float(sum) / n
```
其中 float()函数将 int 类型的 sum 转换成了 float 类型,而 n 无需转换,因为 Python 在计算 float 与 int 混合的表达式时,会自动将 n 转换成 float 类型。
要注意的是,下面这种转换方式是错误的:
```
average = float(sum/n)
```
因为括号里的算式先计算,得到的就是整除结果,然后再试图转换成 float 类型时,已经 为时已晚,小数部分已经丢失了。
其实,调用类型函数来手动转换类型并不是好方法,我们有更简单、更高效的做法。如 果已知的数据都是整数类型的,而我们又希望得到浮点类型的结果,那么我们可以将表达式 涉及的某个整数或某一些整数加上小数点,小数点后面再加个 0,这样整数运算就会变成浮 点运算。例如求两个整数的平均值:
```
>>> x = 3
>>> y = 4
>>> z = (x + y) / 2.0
>>> z
3.5
```
例中我们人为地将数据个数 2 写成了 2.0,这样就使计算结果变成了 float 类型。 当然,在将浮点数转换成整数类型时,就没有这种简便方法了,只能通过类型函数来转换。例如:
```
>>> int(3.8)
3
>>> long(3.8)
3L
```
可见,float 类型转换成 int 或 long 时,只是简单地舍去小数部分,并没有做四舍五入。 如果希望得到四舍五入的结果,一个小技巧是先为该值(正数)加上 0.5 再转换。更一般 的方法是调用内建函数 round(),它专门用于将浮点数转换成最接近的整数部分。不过舍 入后的结果仍然是 float,为了得到 int 类型的数据还需要再用 int()转换。例如:
```
>>> round(3.14)
3.0
>>> round(-3.14)
-3.0
>>> round(3.5)
4.0
>>> round(-3.5)
-4.0
>>> int(round(-3.14))
-3
```
- 前言
- 第 1 章 计算与计算思维
- 1.1 什么是计算?
- 1.1.1 计算机与计算
- 1.1.2 计算机语言
- 1.1.3 算法
- 1.1.4 实现
- 1.2 什么是计算思维?
- 1.2.1 计算思维的基本原则
- 1.2.2 计算思维的具体例子
- 1.2.3 日常生活中的计算思维
- 1.2.4 计算思维对其他学科的影响
- 1.3 初识 Python
- 1.3.1 Python 简介
- 1.3.2 第一个程序
- 1.3.3 程序的执行方式
- 1.3.4 Python 语言的基本成分
- 1.4 程序排错
- 1.5 练习
- 第 2 章 用数据表示现实世界
- 2.1 数据和数据类型
- 2.1.1 数据是对现实的抽象
- 2.1.1 常量与变量
- 2.1.2 数据类型
- 2.1.3 Python 的动态类型*
- 2.2 数值类型
- 2.2.1 整数类型 int
- 2.2.2 长整数类型 long
- 2.2.3 浮点数类型 float
- 2.2.4 数学库模块 math
- 2.2.5 复数类型 complex*
- 2.3 字符串类型 str
- 2.3.1 字符串类型的字面值形式
- 2.3.2 字符串类型的操作
- 2.3.3 字符的机内表示
- 2.3.4 字符串类型与其他类型的转换
- 2.3.5 字符串库 string
- 2.4 布尔类型 bool
- 2.4.1 关系运算
- 2.4.2 逻辑运算
- 2.4.3 布尔代数运算定律*
- 2.4.4 Python 中真假的表示与计算*
- 2.5 列表和元组类型
- 2.5.1 列表类型 list
- 2.5.2 元组类型 tuple
- 2.6 数据的输入和输出
- 2.6.1 数据的输入
- 2.6.2 数据的输出
- 2.6.3 格式化输出
- 2.7 编程案例:查找问题
- 2.8 练习
- 第 3 章 数据处理的流程控制
- 3.1 顺序控制结构
- 3.2 分支控制结构
- 3.2.1 单分支结构
- 3.2.2 两路分支结构
- 3.2.3 多路分支结构
- 3.3 异常处理
- 3.3.1 传统的错误检测方法
- 3.3.2 传统错误检测方法的缺点
- 3.3.3 异常处理机制
- 3.4 循环控制结构
- 3.4.1 for 循环
- 3.4.2 while 循环
- 3.4.3 循环的非正常中断
- 3.4.4 嵌套循环
- 3.5 结构化程序设计
- 3.5.1 程序开发过程
- 3.5.2 结构化程序设计的基本内容
- 3.6 编程案例:如何求 n 个数据的最大值?
- 3.6.1 几种解题策略
- 3.6.2 经验总结
- 3.7 Python 布尔表达式用作控制结构*
- 3.8 练习
- 第 4 章 模块化编程
- 4.1 模块化编程基本概念
- 4.1.1 模块化设计概述
- 4.1.2 模块化编程
- 4.1.3 编程语言对模块化编程的支持
- 4.2 Python 语言中的函数
- 4.2.1 用函数减少重复代码 首先看一个简单的用字符画一棵树的程序:
- 4.2.2 用函数改善程序结构
- 4.2.3 用函数增强程序的通用性
- 4.2.4 小结:函数的定义与调用
- 4.2.5 变量的作用域
- 4.2.6 函数的返回值
- 4.3 自顶向下设计
- 4.3.1 顶层设计
- 4.3.2 第二层设计
- 4.3.3 第三层设计
- 4.3.4 第四层设计
- 4.3.5 自底向上实现与单元测试
- 4.3.6 开发过程小结
- 4.4 Python 模块*
- 4.4.1 模块的创建和使用
- 4.4.2 Python 程序架构
- 4.4.3 标准库模块
- 4.4.4 模块的有条件执行
- 4.5 练习
- 第 5 章 图形编程
- 5.1 概述
- 5.1.1 计算可视化
- 5.1.2 图形是复杂数据
- 5.1.3 用对象表示复杂数据
- 5.2 Tkinter 图形编程
- 5.2.1 导入模块及创建根窗口
- 5.2.2 创建画布
- 5.2.3 在画布上绘图
- 5.2.4 图形的事件处理
- 5.3 编程案例
- 5.3.1 统计图表
- 5.3.2 计算机动画
- 5.4 软件的层次化设计:一个案例
- 5.4.1 层次化体系结构
- 5.4.2 案例:图形库 graphics
- 5.4.3 graphics 与面向对象
- 5.5 练习
- 第 6 章 大量数据的表示和处理
- 6.1 概述
- 6.2 有序的数据集合体
- 6.2.1 字符串
- 6.2.2 列表
- 6.2.3 元组
- 6.3 无序的数据集合体
- 6.3.1 集合
- 6.3.2 字典
- 6.4 文件
- 6.4.1 文件的基本概念
- 6.4.2 文件操作
- 6.4.3 编程案例:文本文件分析
- 6.4.4 缓冲
- 6.4.5 二进制文件与随机存取*
- 6.5 几种高级数据结构*
- 6.5.1 链表
- 6.5.2 堆栈
- 6.5.3 队列
- 6.6 练习
- 第 7 章 面向对象思想与编程
- 7.1 数据与操作:两种观点
- 7.1.1 面向过程观点
- 7.1.2 面向对象观点
- 7.1.3 类是类型概念的发展
- 7.2 面向对象编程
- 7.2.1 类的定义
- 7.2.2 对象的创建
- 7.2.3 对象方法的调用
- 7.2.4 编程实例:模拟炮弹飞行
- 7.2.5 类与模块化
- 7.2.6 对象的集合体
- 7.3 超类与子类*
- 7.3.1 继承
- 7.3.2 覆写
- 7.3.3 多态性
- 7.4 面向对象设计*
- 7.5 练习
- 第 8 章 图形用户界面
- 8.1 图形用户界面概述
- 8.1.1 程序的用户界面
- 8.1.2 图形界面的组成
- 8.1.3 事件驱动
- 8.2 GUI 编程
- 8.2.1 UI 编程概述
- 8.2.2 初识 Tkinter
- 8.2.3 常见 GUI 构件的用法
- 8.2.4 布局
- 8.2.5 对话框*
- 8.3 Tkinter 事件驱动编程
- 8.3.1 事件和事件对象
- 8.3.2 事件处理
- 8.4 模型-视图设计方法
- 8.4.1 将 GUI 应用程序封装成对象
- 8.4.2 模型与视图
- 8.4.3 编程案例:汇率换算器
- 8.5 练习
- 第 9 章 模拟与并发
- 9.1 模拟
- 9.1.1 计算机建模
- 9.1.2 随机问题的建模与模拟
- 9.1.3 编程案例:乒乓球比赛模拟
- 9.2 原型法
- 9.3 并行计算*
- 9.3.1 串行、并发与并行
- 9.3.2 进程与线程
- 9.3.3 多线程编程的应用
- 9.3.4 Python 多线程编程
- 9.3.5 小结
- 9.4 练习
- 第 10 章 算法设计和分析
- 10.1 枚举法
- 10.2 递归
- 10.3 分治法
- 10.4 贪心法
- 10.5 算法分析
- 10.5.1 算法复杂度
- 10.5.2 算法分析实例
- 10.6 不可计算的问题
- 10.7 练习
- 第 11 章 计算+X
- 11.1 计算数学
- 11.2 生物信息学
- 11.3 计算物理学
- 11.4 计算化学
- 11.5 计算经济学
- 11.6 练习
- 附录
- 1 Python 异常处理参考
- 2 Tkinter 画布方法
- 3 Tkinter 编程参考
- 3.1 构件属性值的设置
- 3.2 构件的标准属性
- 3.3 各种构件的属性
- 3.4 对话框
- 3.5 事件
- 参考文献