Python中的截断
我们怎么能在Python中把一个数字的立方根截断到小数点后第十位,而不是四舍五入呢?
举个例子:
如果数字是8,那么我们想要的结果是2.0000000000;如果数字是33076161,结果就是321.0000000000。
4 个回答
num = 17**(1.0/3.0)
num = int(num * 100000000000)/100000000000.0
print "%.10f" % num
当然可以!请把你想要翻译的内容发给我,我会帮你用简单易懂的语言解释清楚。
你只应该在打印结果的时候进行这样的截断(除非你有很重要的理由不这样做)。因为在浮点数格式中,并没有精确的二进制表示,很多日常的十进制值都是这样。
print 33076161**(1.0/3.0)
比如说,计算器给你的答案和Python给的答案可能不一样。即使是Windows计算器在计算cuberoot(33076161)时也能给出一个还不错的结果,而Python的答案在不进行四舍五入的情况下会有微小的错误。
所以,你问的问题本质上是无法回答的,因为它假设了浮点数学中不存在的能力。
错误答案 #1:这个其实是进行四舍五入,而不是截断,但对于你提到的情况,它提供了正确的输出,可能是因为四舍五入弥补了浮点数精度问题,尤其是在情况 #2 中会遇到的问题:
print "%3.10f" % 10**(1.0/3.0)
错误答案 #2:不过你可以将一个11位的四舍五入值截断(作为字符串),但正如有人指出的那样,这在值非常接近进位时会失败,并且在其他奇怪的情况下也会出问题,所以不要这样做:
print ("%3.11f" % 10**(1.0/3.0))[:-1]
合理接近的答案 #3:我写了一个小函数,仅用于显示:
import math
def str_truncate(f,d):
s = f*(10.0**(d))
str = `math.trunc(s)`.rstrip('L')
n = len(str)-d
w = str[0:n]
if w=='':
w='0'
ad =str[n:d+n]
return w+'.'+ad
d = 8**(1.0/3.0)
t=str_truncate(d,10)
print 'case 1',t
d = 33076161**(1.0/3.0)
t=str_truncate(d,10)
print 'case 2',t
d = 10000**(1.0/3.0)
t=str_truncate(d,10)
print 'case 3',t
d = 0.1**(1.0/3.0)
t=str_truncate(d,10)
print 'case 4',t
注意,在情况 #2 中,Python的表现并没有完全符合你的预期,因为浮点数的精度是有限的。
你也许应该了解一下这个文档:
你可能还会对Python的一些附加功能感兴趣,这些功能提供了任意精度的特性,可以让你计算某个数的立方根,精确到你想要的小数位数。使用像mpmath这样的库,你可以摆脱传统浮点数学的精度限制,但这会在性能(速度)上付出相当大的代价。
我觉得内置的十进制单位并没有解决这个问题,因为1/3是一个有理数(循环小数),但它在十进制中是一个无限不循环的小数,因此在十进制表示和浮点数中都无法准确表示:
import decimal
third = decimal.Decimal(1)/decimal.Decimal(3)
print decimal.Decimal(33076161)**third # cuberoot using decimal
输出: 320.9999999999999999999999998
更新:Sven提供了一个很酷的对数用法,适用于这个特定情况,它输出了期望的321值,而不是320.99999...:真不错。我喜欢Log()。不过这适用于321的立方,但在320的立方情况下就失败了:
exp(log(33076161)/3)
看起来分数并没有解决这个问题,但我希望它能解决:
import fractions
third = fractions.Fraction(1,3)
def cuberoot(n):
return n ** third
print '%.14f'%cuberoot(33076161)
缩放 - 截断 - 反缩放:
n = 10.0
cube_root = 1e-10 * int(1e10 * n**(1.0/3.0))