[python] 파이썬은 10의 다음 가장 높은 힘

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)의 다음으로 높은 전력” 이 될 것입니다 :nxn

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

이론적으로는 다른 방향으로 실패하는 것이 가능하지만 이것은 자극하기가 훨씬 더 어려워 보입니다.

따라서 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

이것은 순진한 구현에서는 많은 실패를 발견하지만 개선 된 구현에서는 아무것도 실패하지 않습니다.


답변

차라리 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))

이 같은 것? 그것은 내 머리 꼭대기에서 벗어 났지만 터미널에서 몇 가지 숫자를 시도했을 때 효과가있었습니다.


답변

이것 좀 봐!

>>> 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 가지 경우가 있습니다 :

    1. int( i ) > 1.

    Float수 -로 변환 int후 문자열, str()그것에서는 우리에게 줄 것이다 string으로 length우리가 정확히 찾고이다. 따라서 입력의 첫 부분 은이 길이의 i > 1.010 10의 거듭 제곱입니다.

    1. & 3. 작은 분기 : i > 1.0i > 0.1<=>는 각각 101입니다.
    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촬영 방법이 다를 수 있습니다.

답변