2010-04-20 19 views
23

Ich bin auf der Suche nach dem schnellsten Weg, um eine Ganzzahl-Division in PHP zu tun. zum Beispiel, 5/2 sollte 2 und 6/2 sollte 3 und so weiter sein. Wenn ich das einfach mache, wird PHP im ersten Fall 2.5 zurückgeben, die einzige Lösung, die ich finden konnte, war intval($my_number/2) - was nicht so schnell ist, wie ich es möchte (aber gibt die erwarteten Ergebnisse).Integer-Division in PHP

kann mir jemand dabei helfen?

EDIT:
dank Ihnen allen für Ihre Ideen, habe ich das Skript postet von rubber_boots einige von ihnen mit 10.000.000 Iterationen zu testen, hier können Sie die Ergebnisse (MAMP auf einem 3 oder 4 Jahre alt sehen mit 2 GHz Intel Core 2 Duo) macbook:

start (10000000) 
(int)...: 2.26 sec 
floor(): 4.36 sec 
int_divide(): 2.86 sec 
bit-shift: 1.45 sec //note: only works for divisions through powers of 2 
intval(): 4.51 sec 
round() with PHP_ROUND_HALF_DOWN: 5.48 sec 

bisher Bit-Verschiebung ist der schnellste Weg, aber ich werde diese Frage offen für einen Tag verlassen, wenn es um zu sehen, den andere possibilitys für ist ...

EDIT2:
die Ergebnisse aktualisiert, hinzugefügt round() mit PHP_ROUND_HALF_DOWN (dank Col._Shrapnel)

+4

Einfach nur neugierig, wie in Ihrem Code beteiligten viele Berechnungen so zu machen eine Funktion Leistung-signifikant? –

+8

5/2 sollte 4 sein? Ist das eine php Sache? – nvuono

+0

Ich muss ungefähr 2-3 Millionen Berechnungen machen, wo die Verwendung des intval() - Dinges 30-40 Sekunden dauert (und ich denke, es ist möglich, dies 2 oder 3 mal schneller zu machen) – oezi

Antwort

28

wenn es Division um 2 ist der schnellste Weg, es zu tun, Bit-Verschiebung.

5>>1 = 2 
6>>1 = 3 

und so weiter und so weiter. Was sie tut, ist nur die Bits nach rechts verschieben um 1 Bit, wodurch die Anzahl von 2 Teilen und verlieren den Rest

1110 >> 1 = 111 
1011 >> 1 = 101 
1011 >> 2 = 10 //division by 4 
1011 << 1 =10110 
+5

+1 für den intelligenten Ansatz und für die Aufmerksamkeit auf die Computer-Architektur-Klassen ! – Leonel

+0

Was ist, wenn es nicht Division durch 2 ist? – Pacerier

+0

Dann teilen Sie einfach durch diese Nummer. Division durch eine Potenz von 2 ist ein Sonderfall. Und wird in vielen Fällen verwendet. Zum Beispiel möchten Sie ein HEX-Farbformat in RGB-Werte umwandeln, binär ist die Art, dies zu tun. Ich bin auch auf viele Probleme gestoßen, die elegante Lösungen mit solchen Operationen haben, die zehnmal effizienter sind als Algorithmen, die Dezimalarithmetik verwenden. – AlexanderMP

33

Gerade warf es in einen int:

$result = (int)(6/2); 

Aus irgendeinem Grund ist es viel schneller als intval().

Edit: ich nehme an, Sie suchen eine allgemeinen Integer-Division Lösung. Bit-Verschiebung ist ein Sonderfall zum Teil durch (oder Multiplikation mit) Potenzen von 2 Wenn das interessiert Dich dann:

a/b^n = a >> n where a, b, n are integers 

so:

a/2 = a/2^1 = a >> 1 

aber zwei Einschränkungen:

  1. Viele Compiler/Interpreter werden dies automatisch für Sie tun, so dass es keinen Grund gibt, es zu erraten;

  2. Sofern Sie diese Abteilung mindestens 100.000 Mal in einer einzigen Skriptausführung tun nicht stören. Es ist eine sinnlose Mikrooptimierung.

weiter zu erarbeiten auf (2), ja (int) ist schneller als parseInt() aber ist es wichtig? Fast sicher nicht. Konzentrieren Sie sich auf lesbaren Code und einen guten Algorithmus. Das ist eine irrelevante Ablenkung.

+0

das ist sehr gut, aber ich fand keine schnellere Lösung in der Zwischenzeit - aber vielen Dank für diesen Hinweis. – oezi

+1

"Aus welchem ​​Grund auch immer" => intval() ist eine Funktion, (int) nicht. In PHP haben Funktionen ziemlich viel Overhead, deshalb ist es schneller. "Viele Compiler/Interpreter machen das automatisch für Sie" => PHP ist dumm, es optimiert nicht für Sie. Aber voll und ganz einig "Konzentriere dich auf lesbaren Code und einen guten Algorithmus. Diese Art von Dingen ist eine irrelevante Ablenkung." :) – NikiC

1

die Runde() in der Regel in einem solchen Zweck verwendet. Aber ich habe keine Ahnung von der Geschwindigkeit. Ich hatte nie Millionen von Berechnungen in meinem Code. Lediglich wenige Zehntel max.

+0

round/ceil/floor sind ein bisschen langsamer als intval und roudn gibt falsche Ergebnisse (2.5 wird 3 statt 2) - aber danke für Ihren Versuch – oezi

+0

@oezi Runde kann jedem gewünschte Ergebnisse geben, die eine lesen kann einige Zeilen aus dem Handbuch. Wie auch immer, es ist deine Hardware/schlechtes Anwendungsdesignproblem, nicht PHP-Funktion eins –

+0

ok, meine Schuld, wenn du einen dritten Parameter übergibst, ist es möglich, in diesem Fall runden() runden zu lassen. Ich werde die Ergebnisse in meiner Frage aktualisieren, um diese Option zu betrachten ... – oezi

2

funktioniert nur, wenn $ x und $ y ganze Zahlen sind

function int_divide($x, $y) { 
    return ($x - ($x % $y))/$y; 
} 
1

Verwendung round() oder ceil() oder auf dem Boden() Funktionen, die ansonsten den Typ deklarieren, bevor wie int()

+0

Wie ich in einem anderen Kommentar erwähnt, sind diese Funktionen sogar langsamer als intval() – oezi

4

Gerade Testen Sie es:

Ergebnis (Win32, Core2/E6600):

generic division (3000000) 
(int)DIV:  1.74 sec 
intval(DIV): 6.90 sec 
floor(DIV):  6.92 sec 
int_divide(): 1.85 sec 

division by 2 (3000000) 
(int)(VAL/2): 1.75 sec 
VAL >> 2:  1.63 sec 
(int)(VAL*0.5): 1.72 sec 

Code:

... 
echo "generic division ($N)\n"; 
$start = getTime(); for($i=1; $i<$N; $i++) { $c = (int)(($i+1)/$i); } 
printf("(int)DIV:\t %.2f sec\n", getTime()-$start); 

$start = getTime(); for($i=1; $i<$N; $i++) { $c = intval(($i+1)/$i); } 
printf("intval(DIV):\t %.2f sec\n", getTime()-$start); 

$start = getTime(); for($i=1; $i<$N; $i++) { $c = floor(($i+1)/$i); } 
printf("floor(DIV):\t %.2f sec\n", getTime()-$start); 

$start = getTime(); for($i=1; $i<$N; $i++) { $c = ($i - ($i % ($i+1)))/($i+1); } 
printf("int_divide():\t %.2f sec\n", getTime()-$start); 

echo "division by 2 ($N)\n"; 
$start = getTime(); for($i=1; $i<$N; $i++) { $c = (int)(($i+1)/2.0); } 
printf("(int)(VAL/2):\t %.2f sec\n", getTime()-$start); 

$start = getTime(); for($i=1; $i<$N; $i++) { $c = ($i+1) >> 2; } 
printf("VAL >> 2:\t %.2f sec\n", getTime()-$start); 

$start = getTime(); for($i=1; $i<$N; $i++) { $c = (int)(($i+1)*0.5); } 
printf("(int)(VAL*0.5):\t %.2f sec\n", getTime()-$start); 
... 

Grüße

RBO

5

Heh, ich weiß nicht, wie ich in diese Frage bekam, wie es ab 2010 zu sein scheint, und das ist nicht wirklich eine Antwort, aber wie der Autor scheint alle Möglichkeiten zu sammeln inegers teilen Sie es schnell kann hier jemandem helfen.

Ich verwende normalerweise 0 | anstelle von (int) wenn ich schnell Code für mich schreibe, weil "|" Der Operator hat Vorrang vor den meisten anderen Operatoren, so dass Sie keine zusätzlichen Klammern benötigen.

Selbst
$x=0| 0.3+0.7; 

wird wie erwartet und es ist leicht zu finden, wenn Sie auf Code aussehen (zumindest für mich), wie ich denke nur an „= 0 |“ als spezieller Operator "set and cast to int".

also zu Ihrer Sammlung hinzuzufügen (diese sind einfach nur andere Wege, um int zu werfen):

$c=0| $x/$y; 

und

$c=$x/$y % PHP_INT_MAX; 
+0

wow, danke. Ich habe noch nie von '0 |' gehört. Ich werde das zu meiner Liste hinzufügen, wenn ich zu Hause bin. – oezi