Verbot einer Potenz
-
Hallo,
ich benötige als bedingung für if
daß p2 nicht Potenz sein darf von p1.
Wie kann man das formulieren. Wenn es nur um das Quadrat ginge, wäre es kein Problem.
Wenn P1=7 darf P2 nicht die Werte 47, 343 etc. annehmen.
Danke für den Tip
-
\begin{align} p\_1^x &= p\_2 \\ x &= \log_{p\_1} p\_2 \\ x &= \frac{\ln p\_2}{\ln p\_1} \end{align}Prüfen ob Gl. (3) eine natürliche Zahl ist.
Lieber nochmal überprüfen. Logarithmen waren nie meine Stärke:)Ansonsten ist das eher was fürs 'Rund um die Programmierung' oder Mathematik forum.
-
Ist P2 eine (natürlich ganzzahlige) Potenz von P1, so heisst das, dass das Verhältnis des Logarithmus von P2 zum Logarithmus von P1 ganzzahlig ist.
p2 = p1^n // n e N log(p2) = log( p1^n ) = n * log(p1) bzw.: n = log(p2) / log(p1)in Code gegossen:
#include <cassert> #include <cmath> #include <iostream> bool ist_potenz_von( int x, int base ) { assert( x > 0 && base > 0 ); if( base == 1 ) return x == 1; // 1^egal == x nur für x==1 using namespace std; const double ex = log( double( x ) ) / log( double( base ) ); return ex == floor( ex ); } int main() { using namespace std; const int p1 = 7; for( int p2; cin >> p2; ) { if( ist_potenz_von( p2, p1 ) ) cout << "p2=" << p2 << " ist Potenz von " << p1 << endl; else cout << "p2=" << p2 << " ist KEINE Potenz von " << p1 << endl; } return 0; }Ergibt z.B.:
5 p2=5 ist KEINE Potenz von 7 7 p2=7 ist Potenz von 7 1 p2=1 ist Potenz von 7 49 p2=49 ist Potenz von 7 343 p2=343 ist Potenz von 7 344 p2=344 ist KEINE Potenz von 7 342 p2=342 ist KEINE Potenz von 7Gruß
Werner
-
Das Problem mit Floating-Point-Lösungen ist, dass man mit ungenauen Datentypen rechnet. Werners Lösung liefert mir beispielsweise für 16807 = 7^5 und 282475249 = 7^10 falsche Ergebnisse aufgrund des Rundungsfehlers.
Mit einem Epsilon-Vergleich kann man sich wohl behelfen, aber die Wahl des Epsilons scheint mir nicht trivial.
Ich nehme an, dass eine Low-Tech-Lösung für Integer gesucht ist, beispielsweise
bool is_power_of_aux(int x, int base) { return x == 1 || (x % base == 0 && is_power_of(x / base, base)); } bool is_power_of(int x, int base) { if(base == 0) { return x == 0 || x == 1; } return is_power_of_aux(x, base); }Auch wenn das eine deutlich schlechtere Laufzeitkomplexität hat.
-
seldon schrieb:
Das Problem mit Floating-Point-Lösungen ist, dass man mit ungenauen Datentypen rechnet.
.. kaum hatte ich mein Posting draußen, schon kam mir der gleiche Gedanke.
Ich denke, die Lösung von seldon ist in der Praxis die bessere. Das muss noch nicht mal langsamer sein.
Gruß
Werner
-
Danke Leute, ich muß das jetzt erst verarbeiten...
Eine Low Integer Lösung war gesucht.
-
Nachtrag: Ich meine natürlich
bool is_power_of_aux(int x, int base) { return x == 1 || (x % base == 0 && is_power_of_aux(x / base, base)); }...sonst könnte ich mir das Aussieben von base == 0 auch sparen.
-
Eine vermutlich deutlich schnellere Implementation ist diese hier, da die teure Division vermieden wird:
bool is_power_of_aux(int x, int base) { if (x==1)return true; int rb=base; while (rb<x)rb*=base; return rb==x; }
-
Du müsstest allerdings die Beträge vergleichen oder negative Basen verbieten.
-
Das ist gut.
Noch ein paar Sprzialfälle abchecken.bool is_power_of(unsigned int x, unsigned int base){ switch(base){ case 0: return x<2;//annahme, 0 hoch 0 == 1 case 1: return x==1; case 2: return x!=0 && (x&(x-1))==0; case 3: //??? case 4: unsigned int t=x&0x55555555; return x!=0 && (t&(t-1))==0; case 8: siehe case 4 default: return is_power_of_aux(x,base); } }
-
Vielleicht mag für die Basen<256 eine Tabelle anlegen.
#include <iostream> #include <map> using namespace std; int main(){ map<unsigned int,unsigned int> powerToBase; for(unsigned int base=2;base<256;++base){ for(unsigned int op=0,power=base;power>op;op=power,power*=base){ powerToBase[power]=base; } } cout<<powerToBase.size()<<'\n'; }Sind nur 1360 Einträge. 256 kleine Arrays für binary_search? Oder eine dicke Hashtable? 256 kleine Hashtables?
Zuerst x==1 und x==base abchecken.
Wenn die Basis größer als 65535 ist, reicht return x=basebase.
Wenn die Basis größer als 1625 ist, reicht return x=base*base || x=base*basebase.
Wenn sie größer als 256 ist, reichts bis hoch 4 zu testen.Übrigens ist
while (rb<x)evtl gefährdet durch Überläufe.
Oder vielleicht nur sowas
bool is_power(unsigned int x,unsigned int base){ if(x<=1) if(x==0) return base==0; else return base<=1; unsigned int op; unsigned int power=base; do{ if(power==x) return true; op=power; power*=base; }while(power>op); return false; }