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 함수가 누락 되었습니까?
답변:
math.ceil
함께 사용 하여 다음 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의 지수를 얻게됩니다.
참고 값에 대한 것을 이미 정수는이다 "(10)의 다음으로 높은 전력" 이 될 것입니다 :n
x
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
이론적으로는 다른 방향으로 실패하는 것이 가능하지만 이것은 자극하기가 훨씬 더 어려워 보입니다.
따라서 float 및 int에 대한 강력한 솔루션을 위해서는 로그 값이 대략적인 것으로 가정해야하므로 몇 가지 가능성을 테스트해야합니다. 라인을 따라 뭔가
def nextpow10(n):
p = round(math.log10(n))
r = 10 ** p
if r < n:
r = 10 ** (p+1)
return r;
이 코드는 모든 실제 인수에 대해 정확한 실제 크기 범위에서 올바른 결과를 제공해야한다고 생각합니다. 부동 소수점으로 변환하는 문제로 인해 비 정수 및 비 부동 소수점 유형의 매우 작거나 많은 수의 경우 중단됩니다. 파이썬은 오버플로를 방지하기 위해 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
이 코드는의 10의 거듭 제곱을 기본으로 len( str( int( float_number ) ) )
합니다.
4 가지 경우가 있습니다 :
int( i ) > 1
.Float
수 -로 변환 int
후 문자열, str()
그것에서는 우리에게 줄 것이다 string
으로 length
우리가 정확히 찾고이다. 따라서 입력의 첫 부분 은이 길이의 i > 1.0
10 10
의 거듭 제곱입니다.
i > 1.0
및 i > 0.1
<=>는 각각 10
및 1
입니다.i < 0.1
: 여기에서, 열은 음의 힘을 갖습니다. 쉼표 다음에 0이 아닌 첫 번째 요소를 얻으려면 간격에 ("%.100f" % i ).replace('.','').index( k )
걸쳐 k가있는 그러한 구성을 사용했습니다 [1:10]
. 그런 다음 최소한 결과 목록을 가져 오십시오. 그리고 1 씩 줄이면 처음 0이 계산됩니다. 또한 여기에서 표준 파이썬 index()
은 [1:10]
간격 에서 0이 아닌 요소 중 적어도 하나를 찾지 못하면 충돌 이 발생할 수 있으므로 결국에는 발생별로 목록을 필터링해야합니다 if str( j ) in "%.100f" % i
. 또한, 더 정밀하게하기 위해- %.100f
촬영 방법이 다를 수 있습니다.
10
예를 들어 무언가가 필요합니다log10
.