2010-04-20 24 views
23

Je cherche le moyen le plus rapide de faire une division entière en php. par exemple, 5/2 devrait être 2 et 6/2 devrait être 3 et ainsi de suite. si je fais simplement cela, php retournera 2.5 dans le premier cas, la seule solution que j'ai pu trouver était d'utiliser intval($my_number/2) - ce qui n'est pas aussi rapide que je le veux (mais donne les résultats attendus).division entière en php

Quelqu'un peut-il m'aider avec cela?

EDIT:
grâce à vous tous pour vos idées, j'ai utilisé le script postet par rubber_boots pour tester certains d'entre eux avec 10000000 itérations, ici vous pouvez voir les résultats (MAMP sur 3 ou 4 ans MACBOOK avec intel core 2Ghz 2 duo):

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 

jusqu'à présent, de changement de bit est le moyen le plus rapide, mais je vais laisser cette question ouverte pour une journée pour voir s'il y a d'autres possibilitys pour cette ...

EDIT2:
mis à jour les résultats, round() ajouté avec PHP_ROUND_HALF_DOWN (grâce à Col._Shrapnel)

+4

Juste curieux combien de calculs impliqués dans votre code pour faire une telle une fonction performance-significative? –

+8

5/2 devrait être 4? est-ce une chose php? – nvuono

+0

je dois faire environ 2-3 millions de calculs où l'utilisation de la chose intval() va prendre 30-40 secondes (et je pense que c'est possible de le faire 2 ou 3 fois plus rapide) – oezi

Répondre

28

si sa division par 2, le moyen le plus rapide de le faire est le transfert de bits.

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

et ainsi de suite. Ce qu'il fait est passer juste les bits vers la droite de 1 bit, divisant ainsi le nombre de 2 et de perdre le reste

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

+1 pour l'approche intelligente et pour prêter attention aux classes d'architecture d'ordinateur ! – Leonel

+0

Et si ce n'est pas la division par 2? – Pacerier

+0

Ensuite, il vous suffit de diviser par ce nombre. La division par une puissance de 2 est un cas particulier. Et est utilisé dans beaucoup de cas. Par exemple, vous voulez transformer un format de couleur HEX en valeurs RVB, binaire est le moyen de le faire. J'ai également rencontré de nombreux problèmes qui ont des solutions élégantes utilisant de telles opérations, qui sont des dizaines de fois plus efficaces que les algorithmes utilisant l'arithmétique décimale. – AlexanderMP

33

Il suffit de le jeter aux int:

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

Quelle qu'en soit la raison, il est beaucoup plus rapide que intval().

Edit: Je suppose que vous êtes à la recherche d'une solution de division entier général. Bit-shifting est un cas particulier pour diviser par des puissances (ou en multipliant par) de 2. Si cela vous intéresse alors:

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

donc:

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

Mais deux mises en garde:

  1. De nombreux compilateurs/interprètes le feront automatiquement pour vous, il est donc inutile de le deviner;

  2. Sauf si vous effectuez cette division au moins 100 000 fois dans une exécution de script unique ne dérange pas. C'est une micro-optimisation inutile.

pour élaborer davantage sur (2), oui (int) est plus rapide que parseInt() mais est-ce important? Presque certainement pas. Mettre l'accent sur le code lisible et un bon algorithme. Ce genre de chose est une distraction non pertinente.

+0

c'est très bien, mais j'ai trouvé une solution plus rapide en attendant - mais merci beaucoup pour cet indice. – oezi

+1

"Pour une raison quelconque" => intval() est une fonction, (int) ne l'est pas. En PHP, les fonctions ont un peu de surcharge, c'est pourquoi c'est plus rapide. "Beaucoup de compilateurs/interprètes vont le faire pour vous automatiquement" => PHP est bête, il n'optimise pas pour vous. Mais accord complet sur "Mettre l'accent sur le code lisible et un bon algorithme.Ce genre de chose est une distraction non pertinente." :) – NikiC

1

le rond() habituellement utilisé dans un tel but. Mais je n'ai aucune idée de sa vitesse. Je n'ai jamais eu des millions de calculs dans mon code. Seulement quelques dixièmes max.

+0

rond/plafond/sol sont un peu plus lent que intval et roudn donne des résultats erronés (2.5 deviendra 3 au lieu de 2) - mais merci pour votre essai – oezi

+0

@oezi ronde peut donner des résultats souhaités, à quiconque peut lire un quelques lignes du manuel. de toute façon c'est votre matériel/problème de conception de l'application pauvres, pas la fonction PHP un –

+0

ok, ma faute, si vous passez un troisième paramètre, il est possible de letzt tour() arrondir vers le bas dans ce cas. je mettrai à jour les résultats dans ma question pour considérer cette option ... – oezi

2

ne fonctionne que si $ x et $ y sont des entiers

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

utilisation ronde() ou fonctions ceil() ou sur le sol() déclarer autrement le type avant comme int()

+0

comme je le mentionne dans un autre commentaire, ces fonctions sont encore plus lentes qu'intval() – oezi

4

Juste Testez:

Résultat (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); 
... 

Cordialement

RBO

5

Heh, je ne sais pas comment je suis entré dans cette question car il semble être à partir de 2010 et ce n'est pas vraiment une réponse, mais comme l'auteur semble rassembler tous les moyens de diviser inegers vite il peut aider quelqu'un ici.

J'utilise habituellement 0 | au lieu de (int) quand j'écris du code rapide pour moi-même, parce que "|" l'opérateur a la priorité de l'amant, puis la plupart des autres opérateurs, vous n'avez donc pas besoin de parenthèses supplémentaires. Même

$x=0| 0.3+0.7; 

fonctionnera comme prévu et il est facile à trouver quand vous regardez le code (au moins pour moi) que je viens de penser à « = 0 | » comme opérateur spécial "set and cast to int".

Donc, pour ajouter à votre collection (ceux-ci sont tout simplement d'autres moyens de caster int):

$c=0| $x/$y; 

et

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

wow, merci. Je n'ai jamais entendu parler de '0 |' avant. Je vais ajouter ça à ma liste quand je serai à la maison. – oezi

Questions connexes