前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python 中的进制转换

Python 中的进制转换

作者头像
老齐
发布2021-09-15 11:31:36
2.3K0
发布2021-09-15 11:31:36
举报
文章被收录于专栏:老齐教室老齐教室

★本文是书稿中的一部分,主要介绍了 Python 中进制转换的实现方法。更多内容请参阅 www.itdiffer.com 我的个人网站 ”

3.4 进制转换

前面诸节所用到的整数、浮点数、分数,均是“十进制”的数,这符合数学和日常生产生活的多数习惯。而计算机则不然,它使用的是二进制(参阅第1章1.2节)。从数学角度看,用于实现记数方式的进位制除了十进制、二进制之外,还有八进制、十六进制、六十进制等。同一个数字,可以用不同的进位制表示。在数学和计算机原理的资料中,会找到如何用手工的方式实现各种进位制之间的转换——这些内容不在本书范畴,此处重点介绍使用 Python 内置函数实现进制转换,并由此观察一个貌似“ bug ”的现象。

3.4.1 转换函数

在 Python 内置函数中(如3.3节中的表3-3-1所示)提供了实现数值转换的函数,下面依次介绍。

1. 十进制转换为二进制

内置函数 bin() 能将十进制的整数转换为二进制,例如:

代码语言:javascript
复制
>>> bin(2)
'0b10'
>>> bin(255)
'0b11111111'
>>> bin(-3)
'-0b11'

bin() 只能对十进制的整数进行转换,所返回值是用字符串(参阅第4章4.2节)表示的二进制数字(简称“二进制字符串”),如图3-4-1所示,其中 0b 是二进制字符串前缀。

图3-4-1 返回结果组成

若将十进制的浮点数转化为二进制,是否可以用 bin()?不能!官方文档中很明确地指出:Convert an integer number to a binary string prefixed with “0b”.(https://docs.python.org/3/library/functions.html#bin),还可以试试:

代码语言:javascript
复制
>>> bin(0.1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'float' object cannot be interpreted as an integer

不能使用 bin() 函数将十进制浮点数转化为二进制,但可以用别的方法实现,只不过此处暂不探讨,可以作为读者的一个思考题。

2. 十进制转换为八进制

内置函数 oct() 可以将整数转化为以 0o 为前缀的八进制字符串,如:

代码语言:javascript
复制
>>> oct(8)
'0o10'
>>> oct(256)
'0o400'

注意参数依然必须是整数。

3. 十进制转换为十六进制

内置函数 hex() 可以将整数转化为以 0x 为前缀的十六进制字符串,如:

代码语言:javascript
复制
>>> hex(16)
'0x10'
>>> hex(255)
'0xff'

在十六进制中,一般用数字

0

9

和字母

A

F

表示。在 hex() 返回的十六进制字符串中,所用的

A

F

的字母均为小写。

对于十进制的浮点数,虽然 hexo() 不能使用,但浮点数对象有一个方法可以实现向十六进制的转换。

代码语言:javascript
复制
>>> float.hex(0.1)
'0x1.999999999999ap-4'
>>> 0.1.hex()
'0x1.999999999999ap-4'

其实,这里得到的十六进制字符串与十进制浮点数 0.1 并非严格相等。

4. 二进制转换为十进制

如果在交互模式中直接输入二进制数,比如 01,Python 解释器并不接受——所接受的是十进制数。

代码语言:javascript
复制
>>> 01
  File "<stdin>", line 1
    01
     ^
SyntaxError: leading zeros in decimal integer literals are not permitted; use an 0o prefix for octal integers

当然,有的读者可能输入的是 11 ,不会报错,但 Python 把它看做二进制 11 了吗?没有!它显然被 Python 认定为十进制的整数十一了。

代码语言:javascript
复制
>>> 11
11
>>> type(11)
<class 'int'>

但是,如果在交互模式中这样输入二进制数字:

代码语言:javascript
复制
>>> 0b11
3
>>> 0b10
2
>>> 0b11111111
255

注意,输入的不是“二进制字符串”,而是在二进制数前面写上了前缀 0b,表示当前所输入的是二进制数,返回值则是对应的十进制整数。这种方式仅限于交互模式,在程序文件中不能这样做——千万不要将 >>> 0b11 复制到 .py 文件中。

更常用的方法是使用内置函数 int() ,在3.3.1节中提到过, int(x, base=10) -> integer 会在本节介绍,就是这里:

代码语言:javascript
复制
>>> int('0b10', 2)
2
>>> int('11111111', 2)
255

其中的'0b10''11111111' 都是二进制字符串,并且要设置参数 base=2 ,即说明参数中的数字是二进制数字——不明确“告诉” Python ,它不知道 '0b10''11111111' 表示的是二进制字符串。

同样用 int() 函数,也能将八进制、十六进制的整数转换为十进制的整数。

代码语言:javascript
复制
>>> int('0xff', base=16)
255
>>> int('0o10', base=8)
8

3.4.2 不是 bug

在3.3.1节介绍内置函数 round() 时引用了官方文档的一个示例:

代码语言:javascript
复制
>>> round(2.675, 2)
2.67

该文档中明确说明:“This is not a bug”。那是什么呢?

类似的现象,其实还有,比如:

代码语言:javascript
复制
>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.1 + 0.1 - 0.3
5.551115123125783e-17
>>> 0.1 + 0.1 + 0.1 - 0.2
0.10000000000000003

这些计算中都有一些“误差”,也不是 Python 的 bug。

由于计算机是执行二进制计算的,要完成十进制数字的计算,不得不将十进制数字转化为二进制。对于十进制的整数而言,都有精确的二进制数对应。但是,对于浮点数就不完全有精确的二进制数对应了。

例如,

0.1

转化为二进制是:

0.0001100110011001100110011001100110011001100110011...

。这个二进制数不精确等于十进制数

0.1

。同时,计算机存储的位数是有限制的,所以,就出现了上述“误差”。

这种问题不仅在 Python 中会遇到,在所有支持浮点数运算的编程语言中都会遇到,所以它不是 Python 的 bug 。

明白了原因后,该怎么解决呢?就 Python 的浮点数运算而言,大多数计算机每次计算误差不超过

\frac{1}{2^{53}}

。对于大多数任务来说,通过“四舍五入”(round() 函数,参阅3.3.1节)即能得到期望的结果。

但是,如果遇到“较真”的要求,怎么办?

代码语言:javascript
复制
>>> import decimal
>>> a = decimal.Decimal('0.1')
>>> b = decimal.Decimal('0.2')
>>> a + b
Decimal('0.3')
>>> float(a + b)
0.3

decimal 是 Python 标准库的一个模块,官方地址是 https://docs.python.org/3/library/decimal.html 。如上述代码示例,分别创建了与浮点数

0.1

0.2

对应的两个对象( decimal.Decimal 类型),它们之间相加,所得结果即为准确的

0.3

。但是这样计算的速度要低于浮点数运算。

decimal 模块不仅能解决上述计算“误差”问题,还有很多用途,比如某个业务要求所有计算结果必须有

3

位有效数字(注意与“四舍五入”不同),可以这样实现:

代码语言:javascript
复制
>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 3
>>> Decimal(1) / Decimal(7)
Decimal('0.143')
>>> Decimal(3) * Decimal(math.pi) ** 2
Decimal('29.6')

此外,decimal.Decimal 对象亦有支持常见计算的方法。建议读者在学习完第8章和第9章,再认真阅读此模块的官方文档,并练习使用其中的各个方法。

自学建议 编程语言中是基于计算机基本原理而存在的,因此,建议读者在学习本书之余——学有余力,阅读有关计算机基本原理的书籍,这样不仅对编程语言,乃至于以后的工作实际都会大有裨益。例如对于本节提到的“进制转换带来的计算误差”问题,要想“知其所以然”,就不得不求助于计算机基本原理的知识。 我在个人网站 www.itdiffer.com 和微信公众号【老齐教室】都会发布有关计算机原理的内容,读者可查阅参考。 ”

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 老齐教室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 3.4 进制转换
    • 3.4.1 转换函数
      • 3.4.2 不是 bug
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档