2013-03-12 12 views
5

In python, come è possibile verificare se un numero n è una potenza esatta della base b?come verificare se un numero è una potenza della base b?

Nota: deve essere generalizzato a qualsiasi base fornita come parametro.

Ecco cosa ho ottenuto:

Assumere n e la base sono numeri interi> 0.

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

Non dovresti controllare se il math.log (n, base) è * qualsiasi * intero? –

+3

Perché 'math.log (n, base)' mai uguale 'base ** n'? 128 è una potenza di 2, ma '2 ** 128' non è sicuramente' 7'. – chrisaycock

risposta

9

In primo luogo, a patto di avere un operatore di logaritmo specifico (molti linguaggi forniscono logaritmi per basare 10 o base e solo), logab può essere calcolato come logxb/logxa (dove x è ovviamente una base fornita dalla lingua dell'utente).

Python va meglio perché può elaborare il logaritmo di una base arbitraria arbitraria senza quella complicata uguaglianza di cui sopra.

Quindi in un modo o nell'altro, è possibile ottenere il logaritmo su una base specifica. Da lì, se il registro di b nella base a è un numero intero (nota 1), quindi è una potenza di a.

Così mi piacerebbe iniziare con il seguente codice, ora con il rilevamento dei bordi e minuscole aggiunto:

# 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 

Si veda ad esempio il seguente programma completo che mostra in azione:

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 

Se sei il tipo che è preoccupato per le operazioni in virgola mobile, puoi fare farlo con ripetute moltiplicazioni ma dovresti testare la performa nce di una soluzione del genere poiché è probabile che il software sia notevolmente più lento di quanto non lo sia nell'hardware. Ciò non importa molto per cose come isPower(128,2) ma potrebbe diventare una preoccupazione per isPower(verybignum,2).

Per una variante punto non fluttuante del codice di cui sopra:

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 

Ma assicurarsi che sia testato contro la vostra più grande numero e la base più piccola per essere sicuri di non avere eventuali shock prestazioni.


(Nota 1) tenere a mente la possibilità che in virgola mobile imprecisione può significare che non è esattamente un numero intero. Potrebbe essere necessario utilizzare un confronto "abbastanza vicino".

+1

1) 'math.exp' richiede solo 1 argomento. Se lo aggiusti, allora 2) otterrai la risposta sbagliata per 'isPower (3 ** 10, 3)'. –

+0

Fallisce per i casi limite come 'isPower (1, 1)' – wim

+0

@ Robᵩ, 'exp' era la funzione sbagliata, è stata modificata in' pow'. – 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: Questo codice non falliscono per 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 

lascio al PO di decidere se vuole applicare la correzione banale o riscrivere le sue esigenze.

+0

non riuscito per la base 1 – wim

+0

Vero. Ma lo lascerò al lettore. –

3

Una soluzione molto semplice potrebbe andare in questo modo:

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 

Risultato:

>>> 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 molto buono. potresti voler aggiustare il caso del ciclo infinito con qualcosa come 'ispower (2, 1)'. – wim

+0

@Grazie, risolto. – Akavall

+0

Hai risolto il ciclo infinito, ma hai scritto un bug. 'ispower (2, 1)' dovrebbe essere falso. – wim

0

vorrei dimenticare la roba di registro, che può essere soggetto a complicazioni in virgola mobile, e solo fare questo in modo iterativo :

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 

si potrebbe probabilmente uno-liner con reduce e lambda, ma non sarebbe pignolo farlo.

+0

Non è più efficiente iniziare da '1' e moltiplicare verso' n' per 'base' (o i poteri di' base')? –

+0

Sì, sicuramente, ma c'è già un'altra risposta da fare :) – wim

0

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

Ciò restituirà un valore booleano true o false. Questo dovrebbe funzionare bene. Spero che aiuti

+0

No, prova '(math.log (4913, 17)). Is_integer()' per esempio. –

Problemi correlati