如何设法将math.ceil
数字分配给下一个最高幂10?
# 0.04 -> 0.1
# 0.7 -> 1
# 1.1 -> 10
# 90 -> 100
# ...
我当前的解决方案是检查输入数字范围的字典,但是它是硬编码的,因此我希望使用单线解决方案。也许我在这里错过了一个简单的数学技巧或相应的numpy函数?
如何设法将math.ceil
数字分配给下一个最高幂10?
# 0.04 -> 0.1
# 0.7 -> 1
# 1.1 -> 10
# 90 -> 100
# ...
我当前的解决方案是检查输入数字范围的字典,但是它是硬编码的,因此我希望使用单线解决方案。也许我在这里错过了一个简单的数学技巧或相应的numpy函数?
Answers:
您可以使用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)
为您提供了x
令人满意的解决方案10 ** x == n
,因此,如果四舍五入,x
它将为您提供次幂10的指数。
注意,对于价值n
在那里x
已经是一个整数,则“的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
10 ** math.ceil(math.log10(1)) == 1
,它不是“第二高的幂”
您的问题未指定,您需要退后一步并提出一些问题。
在另一个答案中,建议采用对数,然后取整(上限函数),然后取幂。
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
这在幼稚的实现中发现很多失败,而在改进的实现中没有发现失败。
round
代替math.ceil
?这将引入很多不必要的情况,这r < n
是正确的,因此需要执行其他工作。
看来您想要的是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))
看一下这个!
>>> 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种情况:
int( i ) > 1
。Float
数字-转换为int
,其后为字符串str()
,将为我们提供一个正好string
与length
我们一起寻找的对象。因此,第一部分,对于输入i > 1.0
-它是10
此长度的十次方。
i > 1.0
和i > 0.1
<=> 分别是10
和1
。i < 0.1
:此处,十将为负数。为了获得逗号后的第一个非零元素,我使用了这样的构造("%.100f" % i ).replace('.','').index( k )
,其中k在[1:10]
间隔内运行。此后,取最小的结果列表。减一,它是第一个零,应计数。另外,index()
如果标准python 无法从[1:10]
interval中找到非零元素中的至少一个,则标准python 可能会崩溃,这就是为什么最后我必须通过出现来“过滤”列表的原因if str( j ) in "%.100f" % i
。此外,要更深入地了解- %.100f
可能会有所不同。
10
,这需要使用eglog10
。