返回介绍

建议13:尽量转换为浮点类型后再做除法

发布于 2024-01-30 22:19:09 字数 1846 浏览 0 评论 0 收藏 0

GPA(平均成绩绩点)在出国留学或者奖学金申请中都占有重要的地位。GPA算法有多种形式,其中标准计算方法是将大学成绩乘以课程学分并求和再乘以4,再除以总学分与100之积,一般精确到小数点后两位。假如学生A的各门课程成绩如下:

A课程4学分,成绩96(等级A,绩点4);B课程3学分,成绩85(等级B,绩点3)

C课程5学分,成绩98(等级A,绩点4);D课程2学分,成绩70(等级C,绩点2)

那么该学生的GPA是多少呢?很容易的算术问题对吧,小学生都会!那么你算出来的结果是多少?Python计算出的结果又是多少呢?

>>> gpa = ((4*96+3*85+5*98+2*70)*4)/((4+3+5+2)*100)
>>> print gpa
3

上面的结果跟你计算出的答案一致吗?显然是否定的,你的计算结果为3.62571428571,即使四舍五入保留小数点后两位也应该是3.63。如果有所大学规定的最低GPA是3.5的话,用Python作为GPA计算工具的话可就实实在在会误人前程了。问题出现在哪里呢?这要回到Python设计之初。

Python在最初的设计过程中借鉴了C语言的一些规则,比如选择C的long类型作为Python的整数类型,double作为浮点类型等。同时标准的算术运算,包括除法,返回值总是和操作数类型相同。作为静态类型语言,C语言中这一规则问题不大,因为变量都会预先申明类型,当类型不符的时候,编译器也会尽可能进行强制类型转换,否则编译会报错。但Python作为一门高级动态语言并没有类型申明这一说,因此在上面的例子中你不能提前申明返回的计算结果为浮点数,当除法运算中两个操作数都为整数的时候,其返回值也为整数,运算结果将直接截断,从而在实际应用中造成潜在的质的误差。

Python中除了除法运算之外,整数和浮点数的其他操作行为还是一致的,因此这容易让人产生一种误解,数值的计算与具体操作数的类型(整数还是浮点数)无关,但事实上对于整数除法这是编程过程中潜在的一个危险,因为当你编写一个函数时,即使你希望调用者传入的是浮点类型,但如果不在函数入口进行类型检查或者转换,就无法阻止函数调用者传递整数参数,而往往这种类型的错误还不容易发觉。因此推荐的做法之一是当涉及除法运算的时候尽量先将操作数转换为浮点类型再做运算。

>>> gpa = float(((4*96+3*85+5*98+2*70)*4))/float(((4+3+5+2)*100))
>>> print gpa
3.62571428571

当然随着Python语言的发展,对整数除法问题也做了一定的修正,在Python3中这个问题已经不存在了。Python3之前的版本可以通过from __future__ import division机制使整数除法不再截断,这样即使不进行浮点类型转换,输出结果也是正确的(请读者自行试验)。

最后,还需要说明一点,上例中是使用浮点数才精确,但下列场景又变成了浮点数可能是不准确的。先来看以下代码:

>>> i=1
>>> while i!=1.5:
...   i = i +0.1
...   print i

上面的代码输出会是多少?正确的答案是这段代码会导致无限循环。为什么呢?因为在计算机的世界里,浮点数的存储规则决定了不是所有的浮点数都能准确表示,有些是不准确的,只是无限接近。如0.1转换为二进制表示形式则为0.000110011001……后面1001无限循环。在内存中根据浮点数位数规定,多余部分直接截断,因此当循环到第5次的时候i的实际值为1.5000000000000004(读者可以逐步调试进行验证),则条件表达式i !=1.5显然为True,循环陷入无终止状态。对于浮点数的处理,要记住其运算结果可能并不是完全准确的。如果计算对精度要求较高,可以使用Decimal来进行处理或者将浮点数尽量扩大为整数,计算完毕之后再转换回去。而对于在while中使用i!=1.5这种条件表达式更是要避免的,浮点数的比较同样最好能够指明精度。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文