Python中的截断

0 投票
4 回答
3643 浏览
提问于 2025-04-16 12:50

我们怎么能在Python中把一个数字的立方根截断到小数点后第十位,而不是四舍五入呢?

举个例子:

如果数字是8,那么我们想要的结果是2.0000000000;如果数字是33076161,结果就是321.0000000000

4 个回答

0
num = 17**(1.0/3.0)
num = int(num * 100000000000)/100000000000.0
print "%.10f" % num

当然可以!请把你想要翻译的内容发给我,我会帮你用简单易懂的语言解释清楚。

2

你只应该在打印结果的时候进行这样的截断(除非你有很重要的理由不这样做)。因为在浮点数格式中,并没有精确的二进制表示,很多日常的十进制值都是这样。

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)
2

缩放 - 截断 - 反缩放:

n = 10.0
cube_root = 1e-10 * int(1e10 * n**(1.0/3.0))

撰写回答