python 为什么不解决python math 四舍五入入的 bug

解决大量调用Python subprocess.Popen产生的一些bug - 推酷
解决大量调用Python subprocess.Popen产生的一些bug
自从工作了就好久没发博客,还是出来冒个泡=。=
前段时间写的一个项目需要用python的subprocess.Popen大量调用某shell命令,运行到一定量级之后就会产生内存溢出,造成大量线程阻塞,然后就会造成([Errno 24] Too many open files)这个异常。
网上有人说是close_fds=True这个参数在python2.x默认没打开,这个参数可以关闭文件描述符,试了没有作用。
后来在国外某个人的帖子找到了和我类似的问题,解决办法就是执行后把stdin,stdout,stderr3个流进行清空即可。
结合网上的资料,写了一个可以自定义超时时间调用subprocess.Popen执行shell命令的函数(自定义超时为了避免某些shell卡死的情况),用这个函数去调用subprocess.Popen就不会产生上面这些问题了。
def timeout_command(command, timeout):
start = datetime.datetime.now()
process = subprocess.Popen(command, bufsize=10000, stdout=subprocess.PIPE, close_fds=True)
while process.poll() is None:
time.sleep(0.1)
now = datetime.datetime.now()
if (now - start).seconds& timeout:
process.terminate()
except Exception,e:
return None
return None
out = municate()[0]
if process.stdin:
process.stdin.close()
if process.stdout:
process.stdout.close()
if process.stderr:
process.stderr.close()
process.kill()
except OSError:
return out
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致Python笔记-几种取整方式 - 推酷
Python笔记-几种取整方式
在处理数据的时候,碰到了一个问题,就是取整方式!比如给定一个数值型列表,我需要分别获取它位置为长度的0%,25%,50%,75%,100%处的几个数字。但Python自带的
是向下取整,如果数字长度是5,理论上这五个数字分别对应0%,25%,50%,75%,100%的位置,但使用
,结果却并不是入次。比如当
时,如果加上
int(5*0.75)
,而我想要的应该是4,显然不是我想要的,所以这里需要用到向上取整方式。因此,顺便总结了一下Python的几种取整方式。
下面介绍几种常用的取整方法,包括向下取整、四舍五入、向上取整。
(1)向下取整
向下取整很简单,直接使用int()函数即可,如下代码(Python 2.7.5 IDLE)
&&& a = 3.75&&& int(a)3
(2)四舍五入
第二种就是对数字进行四舍五入,具体的看下面的代码:
&&& a=3.25;b=3.75&&& round(a);round(b)3.04.0
(3)向上取整
但三种,就是向上取整,也就是我这次数据处理中需要的,由于之前没在Python中用到过,所以不太熟悉,其实Python的math中就带了向上取整的函数,即
方法,专门用于向上取整,实例如下:
&&& import math&&& math.ceil(3.25)4.0&&& math.ceil(3.75)4.0
好了,取整方式,大概就是这三种,介绍到此吧!
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致Python 为什么不解决四舍五入(round)的“bug”?
使用 round() 这个函数:&br&&div class=&highlight&&&pre&&code class=&language-python&&&span class=&o&&&&&&/span& &span class=&n&&i&/span&&span class=&o&&=&/span&&span class=&mf&&1.5&/span&
&span class=&o&&&&&&/span& &span class=&n&&ii&/span&&span class=&o&&=&/span&&span class=&nb&&round&/span&&span class=&p&&(&/span&&span class=&n&&i&/span&&span class=&p&&,&/span&&span class=&mi&&0&/span&&span class=&p&&)&/span&
&span class=&o&&&&&&/span& &span class=&n&&ii&/span&
&span class=&mf&&2.0&/span&
&span class=&o&&&&&&/span& &span class=&n&&i&/span&&span class=&o&&=&/span&&span class=&mf&&1.25&/span&
&span class=&o&&&&&&/span& &span class=&n&&ii&/span&&span class=&o&&=&/span&&span class=&nb&&round&/span&&span class=&p&&(&/span&&span class=&n&&i&/span&&span class=&p&&,&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&o&&&&&&/span& &span class=&n&&ii&/span&
&span class=&mf&&1.2&/span&
&span class=&o&&&&&&/span& &span class=&n&&i&/span&&span class=&o&&=&/span&&span class=&mf&&1.245&/span&
&span class=&o&&&&&&/span& &span class=&n&&ii&/span&&span class=&o&&=&/span&&span class=&nb&&round&/span&&span class=&p&&(&/span&&span class=&n&&i&/span&&span class=&p&&,&/span&&span class=&mi&&2&/span&&span class=&p&&)&/span&
&span class=&o&&&&&&/span& &span class=&n&&ii&/span&
&span class=&mf&&1.25&/span&
&span class=&o&&&&&&/span& &span class=&n&&i&/span&&span class=&o&&=&/span&&span class=&mf&&1.45&/span&
&span class=&o&&&&&&/span& &span class=&n&&ii&/span&&span class=&o&&=&/span&&span class=&nb&&round&/span&&span class=&p&&(&/span&&span class=&n&&i&/span&&span class=&p&&,&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span&
&span class=&o&&&&&&/span& &span class=&n&&ii&/span&
&span class=&mf&&1.4&/span&
&span class=&o&&&&&&/span& &span class=&n&&i&/span&&span class=&o&&=&/span&&span class=&mf&&1.415&/span&
&span class=&o&&&&&&/span& &span class=&n&&ii&/span&&span class=&o&&=&/span&&span class=&nb&&round&/span&&span class=&p&&(&/span&&span class=&n&&i&/span&&span class=&p&&,&/span&&span class=&mi&&2&/span&&span class=&p&&)&/span&
&span class=&o&&&&&&/span& &span class=&n&&ii&/span&
&span class=&mf&&1.42&/span&
&/code&&/pre&&/div&&br&奇怪的是四舍五入的规则时而可以时而不行。API 中的解释是:&br&&blockquote&Note&br&The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float.&/blockquote&问题是,为什么内置的库函数 round 不解决下这个问题?
使用 round() 这个函数:…
因为二进制浮点数不能解决这个问题。先看一个现象,和 round 无关的:&&& def show(x):
"""打印一个数,20 位精度"""
print('{:.20f}'.format(x))
&&& show(1.5)
&&& show(1.25)
&&& show(1.245)
&&& show(1.45)
&&& show(1.415)
从数学上看,一个既约分数(有理数)n/d 要表示为 B 进制数,如果 d 的所有素因子都整除 B,就说明存在一个整数 k,使得分母 d 整除 B^k——比如 q * d = B^k,于是此时有 n/d = n / (B^k / q) = nq / B^k,也就是说 n/d 可以使用至多 k 位数的 B 进制小数有限表示。反之,也容易证明,如果 d 有素因子不能整数 B,那么就不存在上面的 k,也就是说有理数 n/d 不可能由有限位数的 B 进制数表示。——也就是说会出现循环小数。对于 10 进制数,所有分母只有素因子 2 和 5 的有理数,都能表示为有限小数。比如 1/2 是 0.5,1/4 是 0.25,1/5 是 0.2,3/8 是 0.375,都是有限的。而对于 2 进制数,分母里面只有素因子 2 的有理数,才能表示为有限小数。所以 1/2 是 0.1,1/4 是 0.01,3/8 是 0.011。但 1/5 就不能用有限二进制数表示了,是个循环小数 0.11……。(什么,你问无理数?小学生都知道无理数是无限不循环小数。)现在:计算机的浮点数是用小数表示的。浮点数就是科学计数法,指数部分是个整数,尾数部分是个小数。计算机的存储是有限的,所以只能使用有限位数的小数表示。计算机硬件通常是用二进制运算的。具体到 Python 的 float,C/C++ 的 float/double,都是有限长度的、二进制、浮点数。准确地说,是这个:现在问题来了。人写程序用十进制数,计算机运行程序用二进制数,怎么办?转换呗。从概念上说,就是我写:a(10) = 0.5计算机读:a(2) = 0.1我写:b(10) = 0.375计算机读b(2) = 0.011可如果我写c(10) = 0.2计算机就只能读成了有限位数,比如 12 位:c(2) = 0.11(咔嚓切断)其实这个被截断保留 12 位二制制位的数用十进制表示是 0.,已经不准了。你说不对呀这个小了,最后一位能不能加上去,让计算机读成c(2) = 0.00(进了一位)这个数用十进制表示则是 0.,又大了。——实际的计算机中,python 的 float 是用 64 位浮点数,其中 53 位是尾数部分,误差小得多了,但还是不可能没有。所以,计算机在把人写的程序转换为内部代码的时候,就必须做十进制到二进制的转换。这个转换就已经不得不带来误差了。当然,像前面说的,不是所有的数都有误差,0.5、3.75、78.625 都不会有误差,但简单的 0.2、3.15 就会有进制转换误差。所以,在开始计算 round 这个四舍五入的函数之前,在程序刚被读入计算机时,这个变量的值早已经不精确了。round 又能解决什么问题?话说回来,round 本身在一些情况下是准确的。比如 0.5、1.5、2.5、3.5 这些数,都能用有限位二进制数表示,它们直接 round 的结果也都是准确的,不过使用的不是四舍五入而是无偏算法(把 0.5 向偶数而不是向上舍入,这里指 Python 3)。round 在另一些情况下又可能是不准确的,因为 Python 的 round 有两个参数,第二个参数表示舍入到第几位,就需要对原数先计算再舍入,就不准确了。如果让 Python 减慢速度,也在内部用十进制表示和计算,就不会出现进制转换和移位这种来源的舍入误差,此时做舍入运算或输入输出就是精确的了。虽然这不能防止其他计算(比如除法、三角函数)带来的误差,但在一些场合,比如金融算钱的时候,还是非常有用的。在 Python 里面可以用 decimal 包来使用十进制浮点数,避免输入输出的带来的进制转换误差,按十进制移位时除法带来的误差等。小结:误差主要来自输入时十进制转换为计算机内部二进制时,且这个问题在有限精度下不可能解决,也不需要解决。round 可以准确舍入,但它涉及的移位计算也可能带来其他误差。Python 的 decimal 包可用于解决这一问题。(写完发现是挖了个古坟,真无趣。)
四舍五入是基于十进制的,在二进制无法精确表示的时候是会有误差的。任何需要十进制运算的地方,都需要用 decimal.Decimal 取代 float:&&& Decimal(1.45)
Decimal('1.1875')
&&& Decimal('1.45')
Decimal('1.45')
&&& Context(prec=2, rounding=ROUND_HALF_UP).create_decimal('1.45')
Decimal('1.5')
&&& Decimal('1.45').normalize(Context(prec=2, rounding=ROUND_HALF_UP))
Decimal('1.5')
&&& Decimal(Decimal('1.45').quantize(Decimal('.1'), rounding=ROUND_HALF_UP))
Decimal('1.5')
不过使用十进制运算的代价就是慢,所以自己抉择吧。
Note that this is in the very nature of binary floating-point: this is not a bug in Python, and it is not a bug in your code either. You’ll see the same kind of thing in all languages that support your hardware’s floating-point arithmetic (although some languages may not display the difference by default, or in all output modes).某些十进制数(如0.1)在机器内部无法用有限数目的二进制位0和1精确表示,只能通过增加固定的位数来提高精度,从而更逼近原来十进制数。round(number[, ndigits])Return the floating point value number rounded to ndigits digits after the decimal point. If ndigits is omitted, it defaults to zero. The result is a floating point number. Values are rounded to the closest multiple of 10 to the power minus ndigits; if two multiples are equally close, rounding is done away from 0.python的round函数定义为 在任意整数*10^(-ndigits) 中取最靠近number的数值,如果有两个整数距离number相等则按照远离0的一侧(负数-0-正数)取值 。round(0.5) is 1.0 and round(-0.5) is -1.0)
有点绕,以round(1.45,1)为例。 任意整数*10^(-1) 最靠近1.45的有1.4(=14*0.1)和1.5(=15*0.1)。看起来二者离1.45距离相等均为0.05,其实1.45在计算机内部用二进制存储的值对应的十进制数值为:&&& from decimal import Decimal
&&& Decimal(2.675)
Decimal('1.1875')
所以此时按照round函数定义,取最靠近1....的值自然就是1.4而不是1.5了。其他的情况类似分析,具体细节参看:
题主测试的和那个bug无关。round是四舍六入五成双的。
python 的官方实现确实有问题,至于为什么作者不改进,原作者可能是什么心态,可以参见刘海洋的答案。大致心态也许是:反正这个错误不在我,所以虽然有方法,但我也不会去解决这个问题。咋一看,很多人会把这个问题理解为浮点数不精确的问题。浮点数不精确,这一点是常识,是对的。但浮点数并非在所有情况下都不精确,也并非「只要浮点数不精确,所涉及的相关计算问题就毫无解决的价值」。Python 的 round 问题是个典型的例子,推测作者的观点是认为这类与浮点数精确度有关的问题没有解决的必要。如同
的观点一样,所以导致了现在的结果。不过仔细分析会发现,0.5 这种浮点数是可以被精确表示的,而 round 这个函数的特定性在于,round 舍入之后的精确性毫无意义。所以 round 这个问题本身造成的不精确性是可以被解决的。对于 round 的不精确性,重要的在于结果是进一还是去尾。我写了一个简单的例子来说明这个问题,当然这个函数在特定情况下也不准确,不过在题目给出的情况下都可以得到正确的结果。#include &stdio.h&
float my_round(float src, int idx)
for (i=idx;i--;)
float dest = (int)src;
if (src &= dest+0.5)
dest += 1;
for (i=idx;i--;)
dest /=10;
return dest;
int main()
printf("result=%f\n", my_round(1.5, 0));
printf("result=%f\n", my_round(1.25, 1));
printf("result=%f\n", my_round(1.245, 2));
printf("result=%f\n", my_round(1.45, 1));
printf("result=%f\n", my_round(1.415, 2));
printf("result=%f\n", my_round(2.675, 2));
我们看到上面的例子中,结论都是正确的。换句话说,以上算法在进一与去尾方面并没有出现错误。认真研究这个问题的来源,涉及到设计上的取舍以及对算法的理解。就是说有限的浮点数在缺少的位置上如何理解。比方说 1.4499999 这种数字,假定是因为 float 的精度原因不能保存更多的位数,那么在精度之外缺少的位置是什么?或者说,乘 10 的时候补什么?——有说法认为应该无限补 9 ,有说法应该无限补 0 。——事实是,当我们让 CPU 执行乘 10 的操作时,它可能选择了补9,而从数学的角度,无限补9,这个数就成了 14.5。我们拿它跟 14.5 这种精确数比较大小,发现它大于等于 14.5。其实大家有兴趣的发现,在同样的 double 范围内的浮点计算中,python 与 lua 的计算结果可能不同,其原因是 lua 对精度进行了一些取舍,导致它在多数计算的结果中更符合大众认知。——这个 round 的问题,为什么乘 10 ,乘 100 可以解决小数点后的舍入误差问题。实际上是 CPU 本身对浮点数进行的补偿。换句话说,虽然 1.45 在保存时产生了误差,但乘十的时候 CPU 试图补偿这种误差。一个简单的例子可以证明 CPU 确实试图补偿:&&& show(f)
&&& show (f*10)
最终,它在于你的选择,是选择 1 呢还是选择 2 呢:反正这个过程错误不在我,所以我也懒得解决这个问题,而且某种极端情况下我恰好是对的。有某种方案能够在多数情况下获得令人期望的结果,虽然它可能造成另外一种极端情况下的问题,但它得到正确结果的概率比出错的概率更大,因此我愿意如此优化。我觉得其实给 python 团队提一个简单的 patch 可以解决这个问题。——当然,流派之争是很可怕的,如同 python 3 刻意的制造不兼容,也可以被认为是好的做法一样。所以 patch 未必会被采纳。
两个问题,一个是浮点数在计算机中的真实存储(这里是在 Python 中的存储)expect:
所以说我们真正给 round 传的数本身就是有问题的啦。Ref: 想要给 round 传真正的数,可以使用 Decimal 模块另一个问题,python 内置 round 的方式,和我们小学学的不同;)所以需要用 Decimal 的 quantize注意 Decimal 默认的四舍五入方式并不是我们所想的那种,根据具体的应用场景查看 rounding 设置即可Ref:
很简单,因为2.675在表示的时候可能是2.6749,所以round以后还是2.67了
你的需求本质是:精确小数运算。然而,float不是为了满足这一需求而设计的,decimal才是。所以,为float单独定制一个round,不符合float的设计意图,也很难实现。以你的函数为例,temp*10这个操作在float下不是精确的。&&& 1.222*1012.999
我的意思是为啥不写个可以解决这个问题的函数:例如(仅仅一个例子,可能从性能啊之类肯定不行,官方是出于什么原因不写一个类似的)def myround(par,l):temp = 1for i in range(l):temp*=10v = int((par+0.5/temp)*temp) / tempreturn vi = 1.25print(myround(i,1))i = 1.245print(myround(i,2))i = 1.21print(myround(i,1))i = 1.249print(myround(i,2))----1.31.251.21.25
他的解释应该说的是这个不是个bug。默认数值都是float,float本来就不精确,所以python应该是只对decimal精确。我觉得这个也挺正常的。
已有帐号?
无法登录?
社交帐号登录求助,两数相加后自动四舍五入?_python吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:70,046贴子:
求助,两数相加后自动四舍五入?收藏
code大概是这样的a = 4.0^(-16) # 就是一个特别小的数b = 3.2c = b + aprint "c =",c出来的结果:c = 3.2&&&
# 跟b的值相等啊,a被自动忽略掉了请问怎么回事啊?还有假如我想指定一个变量的精度,比如精确到小数点后第几位,(不是在print的时候,而是实际内存中的值),应该怎么实现呢?
恩,第二个问题我自己找到答案了指定小数点后位数,用round()函数就可以实现了第一个问题有没有人知道为什么啊
print "%.32f" % a
回复:3楼你这里只是在print a的时候显示到小数点后32位啊我想问的是 明明a是有值的,为什么a+b的值还是等于b呢?感觉好象是python自动把后面的位数给舍去了我确定 不是因为print的原因,c只显示到小数点后一位因为后来我又加了个判断,看b是否和c相等结果b == c,相当于我那个a根本就没有加上去啊
&&& a = 4.0**(-16)&&& b=3.2&&& c = a + b&&& print "c = ",cc =
如果不用print,直接写 c ,则能显示更多位数。以下是有print和无print的输出对比:&&& print c3.&&& c3.8308
恩,上面那边我把b的数值搞错了我试了一下,b小于4.0的时候是正常的但是当b = 4.0的时候,是这样子的&&& a = 4.0e-16&&& b = 4.0&&& c =
a+b&&& c4.0&&&奇怪啊?
继续求助ing
快试试吧,可以对自己使用挽尊卡咯~◆◆
不奇怪,浮点数的运算不是百分百正确的!c语言一般这样判断&if&(a-b&=0.000001)
你给它类型了,感觉就违背了动态语言的特性。
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或

我要回帖

更多关于 python float四舍五入 的文章

 

随机推荐