探索计算之美
2021-10-30王新勇
王新勇
高中信息技术新教材注重理论与实践的结合以及学科本身的科学性和理论性,并且以实现信息意识、计算思维、数字化学习与创新以及信息社会责任四个核心素养的提升为目标。笔者以Python的round()函数作为切入点,对数据与计算的关系和深层链接进行探究。文章中涉及Python的语法规则均以Python3为基础,代码运行环境为python3.8.5版本。
● 发现问题
1.round()函数的概念
round()函数为Python内置(built-in)的函数,Python安装完成后即具有该函数的功能,不需要再引入额外的模块。round()函数提供了低精度的四舍五入的功能,需要重点理解低精度以及四舍五入的原则。
2.round()函数的参数
round()函数提供了两个参数,round(x, n),其中参数x可以是整型(int)、实型(float)或布尔型(bool)的数值,不能是字符串、列表或字典等数据结构类型的值。参数n是一个整数值,为可选参数,用来表示小数点后保留的位数,如round(1.233,2),值为1.23,即小数点后保留2位。参数n可以为负数,当n为负数时,相当于对整数的第n位(-1,对应个位)进行四舍五入,如round(1123,-2),值为1100,如图1所示。n为负整数的情况,非重点探究内容,不做讨论。
3.round()函数取整实验
基于Python的IDLE交互式Shell工具,进行round()函数的取整实验,如图2所示。
对于round(1.3)和round(1.7),是符合四舍五入的原则的。对于round(1.5)和round(2.5),结果为什么都是2?round(3.5)和round(4.5)结果为什么都是4?这是需要思考和探究的第一个问题。
● 追本溯源
1.Python版本差异
如下页图3所示,round()函数在Python3.0版本相比Python2的变化,主要内容包括如下几点:①round()函数从Python3.0开始,对于0.5、1.5、2.5这类小数部分值为0.5的float类型数值,取整时是舍入到偶数的一边。例如,round(2.5),值为2;round(1.5),值也是2。以1.5為例,由于1.5与1和2的距离是一样的,都是0.5的差值,因此,在Python3.0版本开始遵循亲偶数边取整的原则,我们称之为亲偶性。②对于round(x)函数中只有一个参数x的情况,是取整操作,则返回int整型。例如,round(1.555),返回值为2,类型为int。③对于round(x,n)函数中包括两个参数x和n的情况,返回值的类型,与参数x的类型一致,不再是Python2版本中定义的统一返回float类型。例如,round(1,2)返回1,类型为int;round(1.000,2),则返回1.0(等同于1.00),类型为float,如图4所示。
2.round()函数取整总结
根据上述Python3版本的变更分析,可以总结得出round(x)函数的特点为“四舍六入五亲偶”。这里的四舍六入较好理解,对于五亲偶,即针对0.5,1.5,2.5这类小数部分值为0.5的float类型数值,通过round(x)函数取整时,结果是舍入到偶数的一边。对于round(1.5)和round(2.5)的返回值都为2的问题,已经找到了答案。
● 问题拓展
通过round()函数进行float类型数值的保留小数位数的四舍五入实验,发现如下问题:两个数值的小数部分都是0.675,保留两位小数的四舍五入结果为什么不一样呢(如图5)?带着这样的问题,思考float类型数值在计算机中是如何表示的,进一步探究float类型的浮动本质。
● 浮动本质
以0.4和100.4为例,通过print()函数设置参数“%.30f”格式化输出30位小数的方式,来观察Python3的float数值的真实值表示,与原始值相同的部分为17位有效数字,如图6和图7所示。
0.4格式化输出30位小数的数值中红框内的17位有效数字,小数部分占了16位,整数部分为0,占了1位。100.4格式化输出30位小数的数值中红框内的17位有效数字,小数部分占了14位,整数部分为100,占了3位。Python3中float类型数值的精度为17位有效数字。如图8所示,Python3版本基于IEEE-754中对浮点数的定义,确定了17位有效数字来表示float类型数值。
通过float类型数值的判等运算,也可以验证17位有效数字的精度控制,进一步理解float类型数值的浮动本质。对于float类型的数值比较,Python只会取其前17位有效数字的值进行比较,17位有效数字包括整数和小数部分。如下页图9所示,0.4与0.4000000000000001(小数部分的第16位值为1)进行判等比较值为False,是因为0.4等价于0.4000000000000000,第16位值为0,而0.4与0.40000000000000001(小数部分第17位值为1)和0.40000000000000002(小数部分第17位值为2)判等为True,则是因为前17位有效数字部分的值是相同的,小数部分精度范围外的值不参与比较运算。
● 刨根问底
精度范围外的数值是如何产生的?如下页图10所示,0.675小数点后第17位~第30位的值,是如何产生的?需要从float类型的十进制数值转二进制的过程来探究。
1.float类型数值转换为二进制
转换原则:乘2取整,直到小数部分值为0,则转换完成。以数值0.125为例,转换为二进制的过程如下页图11所示。