целочисленное деление в php - PullRequest
23 голосов
/ 20 апреля 2010

Я ищу самый быстрый способ сделать целочисленное деление в php. например, 5/2 должно быть 2 и 6/2 должно быть 3 и так далее. если я просто сделаю это, php вернет 2.5 в первом случае, единственное решение, которое я смог найти, это использовать intval($my_number/2) - что не так быстро, как хотелось бы (но дает ожидаемые результаты).

Кто-нибудь может мне помочь с этим?

EDIT:
спасибо всем за ваши идеи, я использовал скрипт postet by rubber_boots, чтобы протестировать некоторые из них с 10000000 итераций, здесь вы можете увидеть результаты (MAMP на 3 или 4-летнем MacBook с Intel Core 2 Duo 2 ГГц):

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

до сих пор битрейт был самым быстрым способом, но я оставлю этот вопрос открытым на один день, чтобы посмотреть, есть ли другие возможности для этого ...

EDIT2:
обновил результаты, добавил round () с помощью PHP_ROUND_HALF_DOWN (спасибо Col._Shrapnel)

Ответы [ 7 ]

33 голосов
/ 20 апреля 2010

Просто приведите его к int:

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

По какой-то причине, это намного быстрее, чем intval().

Редактировать: I Предположим, вы ищете общее решение целочисленного деления. Сдвиг битов - это особый случай деления (или умножения) на степени 2. Если вас это интересует, то:

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

так:

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

Но две оговорки:

  1. Многие компиляторы / интерпретаторы будут делать это для вас автоматически, поэтому нет смысла угадывать это;

  2. Если вы не выполняете это деление хотя бы 100 000 раз в одиночном выполнении сценария, не беспокойтесь. Это бессмысленная микрооптимизация.

Для дальнейшего уточнения (2), да (int) быстрее, чем parseInt(), но имеет ли это значение? Почти наверняка нет. Сосредоточьтесь на удобочитаемом коде и хорошем алгоритме. Такого рода вещи не имеют значения.

28 голосов
/ 20 апреля 2010

если это деление на 2, самый быстрый способ сделать это - сдвиг битов.

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

и так далее и тому подобное. То, что он делает, это просто сдвигает биты вправо на 1 бит, таким образом, разделяя число на 2 и теряя остальные

1110 >> 1 =  111
1011 >> 1 =  101
1011 >> 2 =   10 //division by 4
1011 << 1 =10110 
5 голосов
/ 18 октября 2011

Хех, я не знаю, как я попал в этот вопрос, как кажется, с 2010 года, и это не совсем ответ, но поскольку автор, кажется, собирает все способы быстро разделить инегеров, это может кому-то помочь.

Я обычно использую 0 | вместо (int), когда я пишу быстрый код для себя, потому что "|" оператор имеет более высокий приоритет, чем большинство других операторов, поэтому вам не нужны дополнительные скобки. Четный

$x=0| 0.3+0.7;

будет работать как положено, и его легко найти, когда вы посмотрите на код (по крайней мере, для меня), так как я просто думаю о "= 0 |" в качестве специального оператора "set and cast to int".

Итак, чтобы добавить в вашу коллекцию (это просто другие способы приведения к int):

$c=0| $x/$y;

и

$c=$x/$y % PHP_INT_MAX;
4 голосов
/ 20 апреля 2010

Просто проверьте это:

Результат (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

Код:

 ...
 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);
 ...

Привет

БВУ

2 голосов
/ 20 апреля 2010

Работает, только если $ x и $ y являются целыми числами

function int_divide($x, $y) {
    return ($x - ($x % $y)) / $y;
}
1 голос
/ 20 апреля 2010

используйте функции round () или ceil () или floor (), иначе объявите тип раньше как int ()

1 голос
/ 20 апреля 2010

round () обычно используется в таких целях.Но я понятия не имею о его скорости.У меня никогда не было миллионов вычислений в моем коде.Всего несколько десятых макс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...