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


44

math.ceil다음으로 가장 높은 10의 거듭 제곱에 숫자가 할당되도록 어떻게 관리 합니까?

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

내 현재 솔루션은 입력 번호의 범위를 확인하는 사전이지만 하드 코딩되어 있으며 한 줄짜리 솔루션을 선호합니다. 어쩌면 여기에 간단한 수학 트릭이나 해당하는 numpy 함수가 누락 되었습니까?


3
@bold는 이러한 솔루션이 처음부터 작동하는 것처럼 보입니다 . 10예를 들어 무언가가 필요합니다 log10.
jonrsharpe

3
당신이 원하는 단어는 "힘"입니다. 어쩌면 당신은 모국어에 대한 잘못된 번역을 얻었을 것입니다.
user2357112는

고마워, 모니카! @bold :이 질문을 찾았지만 다른 문제입니다. Jonrsharpe는 완벽한 답변을 제공했습니다
offeltoffel

2
이것은 또한 크기의 순서 와 관련이 있습니다 . 1은 0 차, 10은 1 차, 100은 2 차 등입니다.
wjandrea

답변:


60

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
로그 기능을 사용하는 것은 내가 생각해 낼 수 없었던 트릭 인 것 같습니다. 나는 이것이 내가 바랐던 것이라고 믿습니다! 감사합니다
offeltoffel

2
주의 : 원하는 행동에 따라 10의 거듭 제곱에서는 작동하지 않습니다. 예를 들어 10 ** math.ceil(math.log10(1)) == 1"다음으로 가장 높은 거듭 제곱"이
아님

5
참고 :이 답변은 부동 소수점 산술에 의존하므로 반올림 오류로 인해 실패 할 수 있습니다. 예를 들어 1000000000000001을 먹이십시오.
플러그 워시

2
@plugwash가 반드시 필요한 것은 아니며, 수학 함수는 십진법을 사용할 수 있습니다.
jonrsharpe

5
예. 다른 유형은 전달할 수 있지만 배정도 부동 소수점 숫자로 변환되어 C "log10"함수로 전달됩니다. 많은 수의 로그가 넘치지 않도록 특별한 경우가 있지만 반올림 오류를 방지하는 것은 없습니다.
플러그 워시

21

문제가 지정되지 않았으므로 물러서서 몇 가지 질문을해야합니다.

  • 어떤 유형의 입력이 있습니까?
  • 어떤 유형의 출력을 원하십니까?
  • 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

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


여기서 더 자세히 설명해 주셔서 감사합니다. jonrsharpe의 답변이 이미 내 문제를 해결했지만이 답변은 유사하지만 더 구체적인 질문이있는 다른 사람들에게 유용 할 수 있습니다.
offeltoffel

1
round대신에 사용 math.ceil합니까? 이것은 사실이 아닌 많은 불필요한 경우를 소개 r < n하므로 추가 작업을 수행해야합니다.
a_guest

1
로그가 어느 방향 으로든 해제 될 수 있기 때문입니다.
플러그 세척

1
은 "개선 된"코드를 사용하지만, 라운드 상한의 낮은 단부와 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1E-317에 대한 실패에 math.ceil 결과로 대체.
플러그 워시

1
(실제로는 괜찮을 것입니다)
plugwash

3

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

방금이 것을 테스트했는데, 대부분의 실제 경우에는 잘 작동하는 것처럼 공감대를 제공하지만 충분히 작은 입력으로 반올림 오류가 발생하는 것으로 보입니다.
ceiling10

0
y = math.ceil(x)
z = y + (10 - (y % 10))

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


0

이것 좀 봐!

>>> 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촬영 방법이 다를 수 있습니다.

설명을 추가하십시오.
Mobin Ranjbar
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.