show | version | enable_checker |
---|---|---|
step |
1.0 |
true |
- 浮点数有三个部分组成
- 符号位
- 负责正负
-
$0$ 就是正 -
$1$ 就是负
- 指数部分
- 负责翻倍
- 以
$01111111$ 为平衡位置 -
$+1$ 相当于乘以$2$ -
$-1$ 相当于除以$2$
- 尾数部分
- 前面有一个
$1$ 不显示 - 默认就是
$1.0$ - 第一位写一个
$1$ 代表$1.1$ - 第二位再写一个
$1$ 代表$1.11$
- 前面有一个
- 符号位
- 那我们回来再看看
$0.1$ - 有的时候也会出现无法理解的情况
- 这出现了误差?!
- 3 个
$0.1$ 相加等于$0.30000000000000004$ - 观察
$0.1$
- 这个算出来
- 确实比
$0.1$ 大 - 加在一起确实超过
$0.3$ 🤪
- 我们前面介绍的都是单精度浮点型 float
- 单精度浮点型 float 总共 4 字节
- 还有一种双精度浮点型 double
- 总共 8 字节
- 那为什么加起来是
$0.30000000000000004$ 呢? - 我们先来看看和的双精度数的二进制形态
-
$0.1+0.1+0.1$ 的双精度形态 \x34\x33\x33\x33\x33\x33\xd3\x3f
-
\x34\x33\x33\x33\x33\x33\xd3\x3f
对应十进制 $0.30000000000000004$ - 前后都能说通
- 可是,这个和
$0.1$ 到底是怎么加的呢?
- 首先获得
$0.1$ 的双精度浮点型的二进制形态 - 刨去前面的符号位和指数部分
- 还剩下总共 52 位 2 进制数
- 如上图选中的数字部分
-
$1001100110011001100110011001100110011001100110011010$ - (可复制到剪切板)
-
分成两部分
- 有效数字
- 指数
-
有效数字
- 前面有个缺省的 1
- 把这 52 位 2 进制数前面补 1
- 并加上小数点
$1.1001100110011001100110011001100110011001100110011010$
- 指数部分
- -4
- 综合起来就是
-
$1.1001100110011001100110011001100110011001100110011010$ ^2-4
-
- 乘以 3 得到有效数字
- 此时的数值是原来的3倍
- 大致是0.3
- 数量级和原来差22
-
ieee-754要求第1位必须有个缺省的1
- 所以小数点要向左移动2位
- 由于是2进制数
- 小数点向左移动2位就相当于要除以 4
-
综合起来就是要对有效数字
- 先✖3
- 再÷4
- 先算有效数字
- 先粘贴有效数字部分
- 再✖3÷4
- 结果向上(ceil)取整
- 并转化为2进制(binary)
- 有效数字是(1.)0011001100110011001100110011001100110011001100110100
- 去掉红框中的1
- 保留后面的有效数字
- 然后转化为 16 进制
$0x3333333333334$
- 依然是 52 位 2 进制数
- 共 13 位 16 进制数
- 指数部分
- 从3FB变成3FD
- 整体是
- 0x3FD3333333333334
- 00111111 11010011 00110011 00110011 00110011 00110011 00110011 00110100
- 可复制出来去binaryconvert.com验证
- 通过系统中的字节状态进行验证
- 与
$0.1+0.1+0.1$ 得到的$0.30000000000000004$ - 对比直接进行的二进制编码
- 这是一致的
- 我可以手算这个过程么?
- 说干就干,走起来~
- 把后 52 位复制出来
- 第一步是相加
- 两个一样的数,左移 1 位
- 然后再加上自身
- 得到结果是尾数
- 尾数以
$1.xxx$ 开头 - 向右移动 2 位
- 然后掐头去掉开头默认的 1
- 结尾多出的两位有进位
- 保持 52 位
- 早年间其实 Guido 的 python 是这样的
- 整型变量可以和整型变量运算
- 浮点型变量可以和浮点型变量运算
- 整型和浮点型之间不能加减乘除
- 为什么呢?
- 指令集不同
- 整型数字加法有自己的指令集
- 浮点型数字加法有自己的指令集
- 没有一个指令能算整型加上浮点型
- 要在系统里把整型转化为浮点型
- 再用浮点型指令集来做
- 早年间甚至有专门负责浮点运算的协处理器
- 想象一下
$1e100 + 1e-100$ - 有效数字需要对齐
- 这个东西虽然有了指令
- 但是还是比较复杂的
- 解决这个问题的是 Tim Peters,美国的一位软件工程师
- 他在 Python 发展的早期,就参与了这个语言的开发和设计。
- 他原来在为大型主机写编译器
- 后来业余时间加入了 python 这个项目
- 他是 Python 语言以及 CPython 的主要 contributor 之一
- 他创造了 Timsort hybrid sorting 算法
- 这个算法从 Python2.3 开始就在使用
- 很硬核
- 原来的整型和浮点型不能相加减
- 他让两个不同类型的数字可以相加
- Python 标准模块中的 doctest 和 timeit,也是他的大作
- 他也是 python 之禅的作者
- 2001 年秋,Foretec(一家会议组织公司)正在准备召开第十届 International Python Conference(IPC 10,Pycon 的前身)
- Foretec 打算征集一条印在会议 T 恤衫上的标语,最终他们从 Python 社区收到了 500 多条投稿
- Foretec 邀请了 Python 的核心开发 Guido,Fred,Jeremy,Tim Peters,Barry 等来担任评审
- 评审委员们从投稿中过滤出了 130 多条后就一直没有进展,直到会议快要召开时他们也没有确定最终标语
- 在会议就要开始的前几天,到了评审们不得不做出决定的时候了
- 于是由 Tim Peters 和 Barry 两人轮流评审,每人每次淘汰一半留下一半,直到最后只剩一条
- 最终,“import this”被选了出来,大家对“import this”非常满意
- 但是当选择了这条以后,他们意识到他们必须要实现它
- 经过简单的讨论后,“import this”的被定为输出 Tim Peters 写的《The Zen of Python》
- ——Python 编程和设计的指导原则。
- this.py 在 lib 里面是标准库
- 去找一下
sudo find / -name "this.py"
- 这是啥?
- 代码中的 s 字符串使用了 rot13 加密
- rot13 就是凯撒密码的一种,每个字母变换为它后面的第 13 个字母
- 等到 IPC 10 结束后
- 他们悄悄的把代码提交到 Python 2.2.1
- 过了一段时间,才逐渐有人发现“import this”这个彩蛋
- 我们现在回头再看这个东西
- 能找到原因了吗?
- 这次了解浮点类型变量
- 有两种表示法
- float 4 字节 单精度浮点型
- double 8 字节 双精度浮点型
- 浮点型特点
- 第一位都是符号
- 小数点都浮动
- 浮动程度由指数部分决定
- 尾数部分默认 1 开头
- 后面的小数部分是有效数字
- 这就是浮点类型的数据
- 不过很容易出错
- 这个问题简直致命!
- 太容易出错
- 尤其是和钱相关的
- 有没有减少出错的方法?
- 最好是十进制理解下的完全正确?🤪
- 下次再说 👋