2013-03-12 6 views
5

In Python, wie können Sie überprüfen, ob eine Zahl n eine genaue Potenz der Basis b ist?Wie überprüft man, ob eine Zahl eine Potenz der Basis b ist?

Hinweis: es muss auf jede Basis verallgemeinert werden, die als Parameter angegeben ist. Hier

ist, was ich habe:

Angenommen, n und Basis sind ganze Zahlen> 0.

import math 
def is_power(n,base): 
    return math.log(n,base) == base**n 
+3

Sollten Sie nicht überprüfen, ob die math.log (n, Basis) * any * ganze Zahl ist? –

+3

Warum wäre 'math.log (n, base)' immer gleich 'base ** n'? 128 ist eine Potenz von 2, aber '2 ** 128' ist definitiv nicht' 7'. – chrisaycock

Antwort

9

Zuerst vorausgesetzt, Sie einen bestimmten Logarithmus Operator haben (viele Sprachen Logarithmen bieten 10 oder Base zu stützen e only), logab kann als logxb/logxa berechnet werden (wobei x offensichtlich eine Basis ist, die Ihre Sprache bietet).

Python geht um eins besser, da es den Logarithmus für eine beliebige Basis ohne die oben genannte knifflige Gleichheit ausarbeiten kann.

So oder so, Sie haben eine Möglichkeit, Logarithmus zu einer bestimmten Basis zu bekommen. Wenn das Protokoll b in der Basis a eine Ganzzahl (Anmerkung 1) ist, dann ist b eine Leistung von a.

Also würde ich mit dem folgenden Code starten, jetzt mit zusätzlichen Rand Fallabfragung:

# Don't even think about using this for negative powers :-) 

def isPower (num, base): 
    if base == 1 and num != 1: return False 
    if base == 1 and num == 1: return True 
    if base == 0 and num != 1: return False 
    power = int (math.log (num, base) + 0.5) 
    return base ** power == num 

zum Beispiel finden Sie in das folgende komplette Programm, das dies in Aktion zeigt:

import math 

def isPower (num, base): 
    if base == 1 and num != 1: return False 
    if base == 1 and num == 1: return True 
    if base == 0 and num != 1: return False 
    power = int (math.log (num, base) + 0.5) 
    return base ** power == num 

print isPower (127,2)  # false 
print isPower (128,2)  # true 
print isPower (129,2)  # false 
print 

print isPower (26,3)  # false 
print isPower (27,3)  # true 
print isPower (28,3)  # false 
print isPower (3**10,3)  # true 
print isPower (3**129,3) # true 
print 

print isPower (5,5)   # true 
print isPower (1,1)   # true 
print isPower (10,1)  # false 

Wenn Sie die Sorte sind, die sich Sorgen über Fließkommaoperationen macht, können Sie mit wiederholten Multiplikationen tun, aber Sie sollten die Performa testen B. eine solche Lösung, da sie in Software wahrscheinlich wesentlich langsamer ist als in Hardware. Das wird für Dinge wie isPower(128,2) nicht viel ausmachen, aber es könnte ein Problem für isPower(verybignum,2) werden.

Für eine Nicht-Floating-Point-Variante des obigen Code:

def isPower (num, base): 
    if base == 1 and num != 1: return False 
    if base == 1 and num == 1: return True 
    if base == 0 and num != 1: return False 
    testnum = base 
    while testnum < num: 
     testnum = testnum * base 
    return testnum == num 

Aber stellen Sie sicher, dass es gegen Ihre größte Zahl und kleinste Basis getestet hat man keine Performance-Schocks nicht bekommen, zu gewährleisten.


(Anmerkung 1) Beachten Sie hier die Möglichkeit, dass Punkt Unschärfen floating bedeuten kann, es ist nicht genau eine ganze Zahl. Sie müssen möglicherweise einen Vergleich "nahe genug" verwenden.

+1

1) 'math.exp' benötigt nur 1 Argument. Wenn Sie das beheben, dann 2) Sie erhalten die falsche Antwort für 'isPower (3 ** 10, 3)'. –

+0

Fehler bei Grenzfällen wie 'isPower (1, 1)' – wim

+0

@ Robᵩ, 'exp' war die falsche Funktion, sie wurde in' pow' geändert. – paxdiablo

-1
>>> def isPower(n, b): 
... return b**int(math.log(n, b)+.5)==n 
... 
>>> isPower(128, 2) 
True 
>>> isPower(129, 2) 
False 
>>> isPower(3**10, 3) 
True 
>>> isPower(3**129, 3) 
True 
>>> isPower(10**500, 10) 
True 
>>> isPower(10**(10**6), 10) 
True 


EDIT: Dieser Code ist nicht für 1,1:

>>> isPower(1,1) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 2, in isPower 
ZeroDivisionError: float division by zero 

Ich werde es den OP verlassen zu entscheiden, ob er die trivialen fix anzuwenden oder seine Anforderungen umschreiben.

+0

schlägt für Basis 1 fehl – wim

+0

Wahr. Aber das überlasse ich dem Leser. –

3

Eine sehr einfache Lösung könnte so gehen:

def ispower(n, base): 

    if n == base: 
     return True 

    if base == 1: 
     return False 

    temp = base 

    while (temp <= n): 
     if temp == n: 
      return True 
     temp *= base 

    return False 

Ergebnis:

>>> ispower(32, 2) 
True 
>>> ispower(81, 3) 
True 
>>> ispower(625, 5) 
True 
>>> ispower(50, 5) 
False 
>>> ispower(32, 4) 
False 
>>> ispower(2,1) 
False 
>>> ispower(1,1) 
True 
+0

+1 sehr gut. Vielleicht möchten Sie die Endlosschleife mit etwas wie 'ispower (2, 1) 'reparieren. – wim

+0

@Thanks, behoben. – Akavall

+0

Sie haben die Endlosschleife repariert, aber Sie haben einen Fehler geschrieben. 'ispower (2, 1)' sollte falsch sein. – wim

0

Ich würde das Protokoll Sachen vergessen, die Floating-Point-Komplikationen unterliegen kann, und dies nur iterativ tun :

def is_power(n, base): 
    if base == 1: 
     # note: the question stated "Assume n and base are integers > 0" 
     return n == 1 
    while n % base == 0: 
     n //= base 
     if n == 1: 
      return True 
    return False 

Sie könnten wahrscheinlich Einzeiler mit reduce und lambda, aber es wäre nicht pythonisch zu tun.

+0

Ist es nicht effizienter, mit "1" zu beginnen und mit "base" (oder mit "base") zu "n" zu multiplizieren? –

+0

Ja, sicher, aber es gibt bereits eine andere Antwort, um das zu tun :) – wim

0

>>>(math.log(int(num),int(base))).is_integer()

Dies wird einen Booleschen Wert entweder wahr oder falsch zurück. Dies sollte gut funktionieren. Hoffe es hilft

+0

Nein, versuchen Sie '(math.log (4913, 17)). Is_integer()' zum Beispiel. –

Verwandte Themen