Python 舍入到 10 的下一个最高幂

Python round to next highest power of 10

我如何设法执行 math.ceil 以便将数字分配给 10 的下一个最高幂?

# 0.04  ->  0.1
# 0.7   ->  1
# 1.1   ->  10  
# 90    ->  100  
# ...

我目前的解决方案是一本检查输入数字范围的字典,但它是硬编码的,我更喜欢单行解决方案。也许我在这里遗漏了一个简单的数学技巧或相应的 numpy 函数?

您可以使用 math.ceil with math.log10 来执行此操作:

>>> 10 ** math.ceil(math.log10(0.04))
0.1
>>> 10 ** math.ceil(math.log10(0.7))
1
>>> 10 ** math.ceil(math.log10(1.1))
10
>>> 10 ** math.ceil(math.log10(90))
100

log10(n) 为您提供满足 10 ** x == n 的解决方案 x,因此如果您向上取整 x,它会为您提供 10 的下一个最高次方的指数。

注意对于值n,其中x已经是一个整数,"next highest power of 10" 将是 n:

>>> 10 ** math.ceil(math.log10(0.1))
0.1
>>> 10 ** math.ceil(math.log10(1))
1
>>> 10 ** math.ceil(math.log10(10))
10

你的问题没有明确说明,你需要退一步问一些问题。

  • 您输入的是什么类型?
  • 你想要什么类型的输出?
  • 对于小于 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

这会在原始实现中发现很多失败,但 none 在改进后的实现中。

看看这个!

>>> i = 0.04123
>>> print i, 10 ** len(str(int(i))) if int(i) > 1 else 10 if i > 1.0 else 1 if i > 0.1 else 10 ** (1 - min([("%.100f" % i).replace('.', '').index(k) for k in [str(j) for j in xrange(1, 10) if str(j) in "%.100f" % i]]))               
0.04123 0.1
>>> i = 0.712
>>> print i, 10 ** len(str(int(i))) if int(i) > 1 else 10 if i > 1.0 else 1 if i > 0.1 else 10 ** (1 - min([("%.100f" % i).replace('.', '').index(k) for k in [str(j) for j in xrange(1, 10) if str(j) in "%.100f" % i]]))                 
0.712 1
>>> i = 1.1
>>> print i, 10 ** len(str(int(i))) if int(i) > 1 else 10 if i > 1.0 else 1 if i > 0.1 else 10 ** (1 - min([("%.100f" % i).replace('.', '').index(k) for k in [str(j) for j in xrange(1, 10) if str(j) in "%.100f" % i]]))                   
1.1 10
>>> i = 90
>>> print i, 10 ** len(str(int(i))) if int(i) > 1 else 10 if i > 1.0 else 1 if i > 0.1 else 10 ** (1 - min([("%.100f" % i).replace('.', '').index(k) for k in [str(j) for j in xrange(1, 10) if str(j) in "%.100f" % i]]))                    
90 100

此代码基于len(str(int(float_number)))中的十次方原理。

有4个案例:

    1. int(i) > 1.

      Float 数字 - 转换为 int,之后是字符串 str(),将为我们提供一个 stringlength,这就是我们正在寻找的确切地。因此,第一部分,对于输入 i > 1.0 - 这个长度的幂是十 10

    1. & 3.小分支:i > 1.0i > 0.1<=>分别是101
    1. 最后一种情况,当i < 0.1:这里,十应该是负幂。为了获得逗号后的第一个非零元素,我使用了这样的结构 ("%.100f" % i).replace('.', '').index(k),其中 k 运行 在 [1:10] 区间内。此后,取最少的结果列表。再减一,先为零,再算。此外,这里标准 python 的 index() 可能会崩溃,如果它不会从 [1:10] 间隔中找到至少一个非零元素,这就是为什么最后我必须 "filter" 按出现次数列出:if str(j) in "%.100f" % i。 此外,为了更精确 - %.100f 可能会有所不同。

看来您想要的是 10 的最低次方... 这是一种使用纯数学而不是对数,而是递归的方法。

def ceiling10(x):
    if (x > 10):
        return ceiling10(x / 10) * 10
    else:
        if (x <= 1):
            return ceiling10(10 * x) / 10
        else:
            return 10
for x in [1 / 1235, 0.5, 1, 3, 10, 125, 12345]:
    print(x, ceiling10(x))
y = math.ceil(x)
z = y + (10 - (y % 10))

也许是这样的?它就在我的脑海中,但当我在终端中尝试几个数字时它起作用了。

我认为最简单的方法是:

import math


number = int(input('Enter a number: '))
next_pow_ten = round(10 ** math.ceil(math.log10(number)))
print(str(10) + ' power ' + str(round(math.log10(number))) + ' = '\
      + str(next_pow_ten))

希望对你有所帮助。