Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Power für Integer?


Heiko - Fr 13.05.05 20:18
Titel: Power für Integer?
Gibt es ein Power das nur Integer (Byte reicht auch) erwartet und Integer zurückgibt?
Ich will immer 2^0, ..., 2^7 berechnet haben, will aber das Ergbnis nicht runden. IntPower ist leider das gleiche wie Power, macht also nicht was der Name sagt.


delfiphan - Fr 13.05.05 20:20

Jo: 1 shl Exponent (= 2^Exponent)

IntPower ist nicht dasselbe wie Power. IntPower ist für ganzzahlige (d.h. auch negative) Exponenten.


retnyg - Fr 13.05.05 20:39

ansonsten:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
function hoch(base,exp:integer):int64;
// (c) retasmtools
var i : integer;
begin
    result := 1;
    for i := 1 to exp do result := result * base;
end;


delfiphan - Fr 13.05.05 21:01

Etwas Off-Topic aber trotzdem: Bei user profile iconretnyg's Prozedur wird die Basis exp-mal zu 1 multipliziert. Eine solche Iteration ist vor allem für grössere Exponenten (bei mir aber schon ab sehr kleinen wie 4) langsamer als IntPower+Runden.
Dafür ist die Genauigkeit bei seiner Methode (mit Int64 gerechnet) garantiert.

PS:
Etwas praxisfern, aber theoretisch könnte man zuerst die Primfaktorenzerlegung von exp vornehmen und über diese Zahlen iterieren.
Beispiel 3^18 => statt 3*3*3*3*3*3*... 18-mal auszuführen, könnte man einfach ((3^3)^3)^2 rechnen. Aber okay. Bis man die Zahl faktorisiert hätte, ginge es wohl länger ;)


BenBE - Fr 13.05.05 21:59

Schneller geht es über die Binär-Darstellung vom Exponenten:

Exp = 0 --> 1
Exp = 1 --> Basis
Exp and 1 = 0 --> Power(Basis, Exp shr 1);
Exp and 1 = 1 --> Power(Basis, Exp shr 1) * Basis;

Sonderfälle:
0^0 --> Exception
Basis = 0, Exp <> 0 --> 0;


raziel - Fr 13.05.05 22:05

user profile iconBenBE hat folgendes geschrieben:
0^0 --> Exception

Wieso das? 0^0 = 1


BenBE - Fr 13.05.05 22:15

user profile iconraziel hat folgendes geschrieben:
user profile iconBenBE hat folgendes geschrieben:
0^0 --> Exception

Wieso das? 0^0 = 1

Nein, weil dann folgende Bedingung gelten müsste:


Quelltext
1:
lim(Basis^0, Basis --> 0) = lim(0^Exp, Exp --> 0)                    

Diese kann aber nicht gelten, da 0^Exp nicht stetig über dem Definitionsbereich abgeleitet werden kann.

Außerdem gibt es noch genug andere Widersprüche dieser Definition.


delfiphan - Fr 13.05.05 22:16

@BenBE:
Du meinst sowas: (?)
3^18 => 3^(16+2) => 3^16*3^2 => Power(3,16)*Power(3,2)

Das ergibt 16+2 = 18 Multiplikationen.
Für ((3^3)^3)^2 sind aber nur 8 Multiplikationen nötig. Bzw. wenn du schon Power aufrufst, dann nur einmal, um gleich das Schlussresultat zu erhalten (=> 1 x exp und 1 x ln).

Oder hab ich was falsch verstanden?

@raziel:
lim 0^x = 0
x->0
Aber:
lim x^0 = 1
x->0

(Jedoch gibt es tatsächlich Taschenrechner, die für 0^0 einfach 1 rausspucken.)

//Edit: BenBE war schneller ;O


BenBE - Fr 13.05.05 22:27

user profile icondelfiphan hat folgendes geschrieben:
@BenBE:
Du meinst sowas: (?)
3^18 => 3^(16+2) => 3^16*3^2 => Power(3,16)*Power(3,2)

Nicht ganz:
3^18 => (3^9)^2 => ((3^4)^2 * 3)^2 => (((3^2)^2)^2 * 3)^2

Das sind zwar ein paar mehr Multiplikationen (für kleine Zahlen), aber es entfällt der Aufwand für's Faktorisieren.

Außerdem wird diese Methode auch häufig zum Potenzieren Modulo genutz (z.B. bei Rabbin-Miller und RSA).


retnyg - Fr 13.05.05 22:39

user profile iconBenBE hat folgendes geschrieben:
Schneller geht es über die Binär-Darstellung vom Exponenten:

Exp = 0 --> 1
Exp = 1 --> Basis
Exp and 1 = 0 --> Power(Basis, Exp shr 1);
Exp and 1 = 1 --> Power(Basis, Exp shr 1) * Basis;

Sonderfälle:
0^0 --> Exception
Basis = 0, Exp <> 0 --> 0;

könntest du das in ne delphi funktion verpacken ?


BenBE - Fr 13.05.05 22:57

user profile iconretnyg hat folgendes geschrieben:
user profile iconBenBE hat folgendes geschrieben:
Schneller geht es über die Binär-Darstellung vom Exponenten:

Exp = 0 --> 1
Exp = 1 --> Basis
Exp and 1 = 0 --> Power(Basis, Exp shr 1);
Exp and 1 = 1 --> Power(Basis, Exp shr 1) * Basis;

Sonderfälle:
0^0 --> Exception
Basis = 0, Exp <> 0 --> 0;

könntest du das in ne delphi funktion verpacken ?



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
Procedure FastPower(B, E: Integer): Int64;
begin
    If B = 0 Then
    Begin
        If E = 0 Then Raise EInvalidOperation.Create('Calculating 0^0.');
        Result := 0;
        Exit;
    end;

    If E = 0 Then
    Begin
        Result := 1;
        Exit;
    end
    else if E = 1 Then
    Begin
        Result := B;
        Exit;
    end
    else if E and 1 = 0 Then
    Begin
        Result := FastPower(B, E shr 1);
        Result := Sqr(Result);
        Exit;
    end
    else 
    Begin
        Result := FastPower(B, E shr 1);
        Result := Sqr(Result) * B;
        Exit;
    end;
end;


Für E >= 0!!!


Heiko - Sa 14.05.05 09:37

user profile icondelfiphan hat folgendes geschrieben:
IntPower ist nicht dasselbe wie Power. IntPower ist für ganzzahlige (d.h. auch negative) Exponenten.


Aber keine vollständiger Power mit Integer. Der Exponent ist nur ein Integer. Ich will aber Base, Exponent und Result als Integer (oder Byte).

Aso und ihr habt ja auch ein paar andere Vorschläge gemacht, die ich leider nicht richtig gebrauchen kann, da ich jedes 8. mal 2^0 brauche. Ich werde es jetzt wohl anders Regeln


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure IntegerPowerOfTwo(Exponent: Byte);
begin
 case Exponent of
  0: Result:=1;
  1: Result:=2;
  2: Result:=4;
  3: Result:=8;
  4: Result:=16;
  5: Result:=32;
  6: Result:=64;
  7: Result:=128;
end;


Ich hatte eigentlich keine Lust so eine Prozedur mit einzubauen, weshalb ich es mit Power machen wollte. Aber ich glaube bald, dass die Variante am schnellsten sein wird, da ich ja weiß welche Exponenten und Basen ich immer habe, wodurch ich schon das Ergebnis in den Quellcode reinimplementieren kann. Die Variante mit round (oder Trunc) wird sicherlich nicht schneller sein.

Trotzdem thx für die Antworten. Wenn es bessere Varianten gibt bin ich immer noch offen :wink: .


delfiphan - Sa 14.05.05 11:12

user profile iconHeiko: Du hast den ersten Teil meines ersten Beitrags einfach ignoriert :?

1 shl Exponent ist die Lösung.

(1 shl 0) = 1
(1 shl 1) = 2
(1 shl 2) = 4
(1 shl 3) = 8
(1 shl 4) = 16
...

(Die Bemerkung ist jetzt zwar überflüssig, trotzdem: Statt ein solches Case wäre es wohl geschickter, eine konstante array zu definieren)


Heiko - Sa 14.05.05 12:05

sry. Ich hatte ihn nicht ignoriert, aber vergessen, da ich die anderen gelesen noch hatte.

thx delfiphan für deine Erinnerung :wink: .


retnyg - Sa 14.05.05 13:52

user profile iconHeiko hat folgendes geschrieben:


Delphi-Quelltext
1:
procedure IntegerPowerOfTwo(Exponent: Byte);                    
Wenn es bessere Varianten gibt bin ich immer noch offen

wenn du deine prozeduren schnell machen willst, solltest du keine anderen variablentypen als 32bittige verwenden, da der prozessor sonst immer erst konvertieren muss

meine bruteforce-passwort generator prozedur wurde alleine durch umstellen einiger variablen von byte auf dword um gut 20% schneller


Heiko - Sa 14.05.05 17:42

Ich brauche das immer als Byte, da ich immer Byteweise bei meinem Packprogramm schreibe :wink: , ansonsten nehem ich auch immer Integer oder Cardinal.