2011-02-20

Как работают сервисы типа "shorten URL"?

Не так давно мне понадобилось реализовать свою генерацию коротких URL. Существует масса сервисов по укорачиванию URL: bit.ly, is.gd... Продолжать можно очень долго.
Возник вопрос, а как же работает этот алгоритм? В коротком URL, как правило, могут присутствовать символы a-z, A-Z, 0-9, возможно, еще какие-то спецсимволы.

Таким образом, попытаемся представить, что на выходе у нас получается 62-ричное число. На вход же подается очень большая строка, которую также можно представить в виде N-ричного числа, где N, очевидно, заведомо больше 62.

Тут точного ответа по поводу, как именно работают эти сервисы, дать невозможно. Но можно предположить, что у них есть глобальный счетчик 10-ричных чисел, его числа они и переводят в 62-ричную систему счисления. И существует таблица, ставящая в соответствие URL - short URL. Таким образом, до 3 символов включительно могут соответствовать количеству URL:

62 * 62 * 62 = 238328

Применительно к практике, не всегда можно использовать столь небольшие числа. Например, при переводе MD5 хеша в 62-ричное число, разрядность числа превосходит разрядность регистров процессора и обычными инструкциями оперировать уже не получается. Поэтому на помощь приходит так называемая Длинная арифметика и модуль для PHP BC Math.

Немного погуглив, я натолкнулся на такую функцию, которая и выполняет всю работу (жаль, автор был немец и пришлось рефакторить названия переменных):

function bc_base_convert($value, $frombase, $tobase)
{
 $stock = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
 if (max($frombase, $tobase) > strlen($stock)) {
  trigger_error('Bad Format max: ' . strlen($stock), E_USER_ERROR);
 }
 if (min($frombase, $tobase) < 2) {
  trigger_error('Bad Format min: 2', E_USER_ERROR);
 }
 $decimal = '0';
 $level = 0;
 $result = '';
 $value = trim((string) $value, "\r\n\t +");
 $sign = '-' === $value[0] ? '-' : '';
 $value = ltrim($value, "-0");
 $len = strlen($value);
 for ($i = 0; $i < $len; $i++) {
  $temp = strpos($stock, $value[$len - 1 - $i]);
  if (false === $temp) {
   trigger_error('Bad Char in input 1', E_USER_ERROR);
  }
  if ($temp >= $frombase) {
   trigger_error('Bad Char in input 2', E_USER_ERROR);
  }
  $decimal = bcadd($decimal, bcmul(bcpow($frombase, $i), $temp));
 }
 if (10 == $tobase) {
  return $sign . $decimal;
 }
 while (1 !== bccomp(bcpow($tobase, $level++), $decimal)) {
 }
 for ($i = $level - 2; $i >= 0; $i--) {
  $factor = bcpow($tobase, $i);
  $number = bcdiv($decimal, $factor, 0);
  $decimal = bcmod($decimal, $factor);
  $result .= $stock[$number];
 }
 $result = empty($result) ? '0' : $result;
 return $sign . $result;
}

Первым параметром подается число (может быть и строка с MD5, например). Второй и третий параметры используются для указания из какой в какую систему счисления переводить число.
Массив $stock может быть модифицирован, например, если вы хотите использовать 63 или более -ричную систему счисления. Эта функция по умолчанию поддерживает переводы чисел в систему счисления до 62-ричных включительно.

Надеюсь, что смог помочь ищущим истину людям. :)

2011-02-19

Сравнение последних сборок браузеров в SunSpider

Сегодня решил снова провести тестирование браузеров в, наверное, всеми известном бенчмарке SunSpider. Были взяты следующие подопытные:
  • Mozilla Firefox 4.0 beta 12 pre (2011-02-18)
  • Google Chrome 11.0.672.2 beta
  • Opera 11.10 build 2005 alpha
  • Internet Explorer 9.0.8080.16413 RC
Safari в этот раз не вошел в результаты тестирования. Но я его также протестировал с целью нормализации последствий разгона своего процессора и памяти.
Тесты проводились в наиболее нейтральном и одинаковом рабочем окружении. Тестовая кофигурация:
  • Intel Core 2 Quad Q6600  @ 3.10GHz
  • DDR2 @ 516MHz (5-5-5-18)
Результаты тестирования:
 
Результаты тестирования браузеров в SunSpider 0.9.1
В этот раз перед моими глазами предстала довольно интересная картина. Несмотря на разгон процессора и памяти на моей машине (30% производительности, если сравнивать по старой версии Safari), результаты позволяют сделать вывод, что, например, Mozilla сделала свой браузер приблизительно в 1.2-1.5 раза быстрее. Эти 2 месяца разработчики браузеров не сидели просто так.
Впечатляют результаты IE9 в этом бенчмарке, хотя ходят слухи, что он просто заточен под быстрое прохождение этого теста.
Opera удалось обогнать Chrome, что должно послужить стимулом инженерам гуглобраузера. По сути, Chrome практически никак не сдвинулся в плане скорости исполнения JavaScript. И если так пойдет и дальше, то ему в спину скоро будет дышать даже неповоротливый некогда Firefox.
 
На этом все, будем ждать следующей итерации этапа развития современных браузеров.