您的问题未明确说明,您需要退后一步并提出一些问题。
- 您的输入是什么类型?
- 您希望输出什么类型?
- 对于小于 1 的结果,您究竟要舍入到什么?您想要 10 的实际幂还是 10 的幂的浮点近似值?您知道 10 的负幂不能精确地用浮点数表示吗?我们现在假设您需要 10 次方的浮点近似值。
- 如果输入正好是 10 的幂(或 10 的最接近的浮点近似值),输出是否应该与输入相同?还是应该是 10 的下一个幂? “10 -> 10”还是“10 -> 100”?让我们暂时假设前者。
- 您的输入值可以是相关类型的任何可能值吗?还是他们更受限制。
在另一个答案中,建议取对数,然后四舍五入(天花板函数),然后取幂。
def nextpow10(n):
return 10 ** math.ceil(math.log10(n))
不幸的是,这会出现舍入错误。首先,将 n 从它碰巧拥有的任何数据类型转换为双精度浮点数,这可能会引入舍入误差,然后计算对数可能会在其内部计算和结果中引入更多舍入误差。
因此,我很快就找到了给出错误结果的示例。
>>> import math
>>> from numpy import nextafter
>>> n = 1
>>> while (10 ** math.ceil(math.log10(nextafter(n,math.inf)))) > n:
... n *= 10
...
>>> n
10
>>> nextafter(n,math.inf)
10.000000000000002
>>> 10 ** math.ceil(math.log10(10.000000000000002))
10
理论上它也有可能在另一个方向上失败,尽管这似乎更难激怒。
因此,对于浮点数和整数的稳健解决方案,我们需要假设我们的对数值只是近似值,因此我们必须测试几种可能性。类似于
def nextpow10(n):
p = round(math.log10(n))
r = 10 ** p
if r < n:
r = 10 ** (p+1)
return r;
我相信这段代码应该在一个合理的真实世界范围内为所有参数给出正确的结果。由于将它们转换为浮点的问题,它会因非常少或非常多的非整数和非浮点类型而中断。 Python 特殊情况下 log10 函数的整数参数试图防止溢出,但仍然有足够大的整数,可能会由于舍入错误而导致不正确的结果。
为了测试这两个实现,我使用了以下测试程序。
n = -323 # 10**-324 == 0
while n < 1000:
v = 10 ** n
if v != nextpow10(v): print(str(v)+" bad")
try:
v = min(nextafter(v,math.inf),v+1)
except:
v += 1
if v > nextpow10(v): print(str(v)+" bad")
n += 1
这发现在幼稚的实现中有很多失败,但在改进的实现中没有。