Понимание побитовых операций в JavaScript - PullRequest
4 голосов
/ 17 июня 2009

В настоящее время я храню данные в XML-документе в двоичном виде, длиной 20 цифр, каждая из которых представляет логическое значение.

<matrix> 

    <resource type="single"> 
        <map>10001010100011110000</map> 
        <name>Resource Title</name> 
        <url>http://www.yoursite.com</url> 
    </resource>

</matrix>

Я анализирую это с помощью jQuery и в настоящее время использую цикл for и charAt(), чтобы определить, нужно ли делать что-либо, если значение == "1".

for (var i = 0; i < _mapLength; i++) {
    if (map.charAt(i) == "1") {
        //perform something here
    }
}

Это происходит несколько раз как часть ОГРОМНОГО цикла, который работает довольно медленно. Кто-то сказал мне, что я должен использовать побитовые операторы для обработки этого, и он будет работать быстрее.

Мой вопрос:

Может кто-нибудь предложить мне пример того, как я могу это сделать? Я пытался читать онлайн-уроки, и они, кажется, летят прямо над моей головой. (К вашему сведению: я планирую создать скрипт Ruby, который преобразует мои двоичные 0 и 1 в биты в моем XML.)

Или кто-нибудь знает хороший, простой (может быть, даже тупой вариант) учебник или что-то, что могло бы помочь мне понять эти концепции побитовых операторов?

Ответы [ 4 ]

13 голосов
/ 17 июня 2009

Предполагая, что у вас не более 32 бит, вы можете использовать встроенную в JavaScript функцию parseInt() для преобразования строки из 1 и 0 в целое число, а затем проверить флаги с помощью оператора & (и):

var flags = parseInt("10001010100011110000", 2); // base 2

if ( flags & 0x1 )
{
   // do something
}

...

Смотри также: Как проверить мой байт-флаг?

(вопрос об использовании в C, но относится и к тем же операторам в JS)

3 голосов
/ 29 июня 2009

Будьте предельно осторожны. Javascript не имеет целых чисел - числа хранятся как 64-битные с плавающей точкой. Вы должны получить точное преобразование в 52 бита. Если вы получите больше флагов, чем это, плохие вещи произойдут, когда ваше «число» будет округлено до ближайшего представимого числа с плавающей запятой. (Ой!)

Кроме того, побитовая манипуляция не поможет производительности, потому что число с плавающей запятой будет преобразовано в целое число, проверено, а затем преобразовано обратно.

Если у вас есть несколько мест, где вы хотите проверить флаги, я бы установил флаги для объекта, желательно с именами, например:

var flags = {};
flags.use_apples = map.charAt(4);
flags.use_bananas = map.charAt(10);

и т.д ...

Затем вы можете проверить эти флаги внутри вашего цикла:

if(flags.use_apples) {
    do_apple_thing();
}

Тестирование слота объекта будет быстрее, чем битовая проверка, поскольку Javascript не оптимизирован для битовых операторов. Однако, если ваш цикл медленный, я боюсь, что декодирование этих флагов, вероятно, не является источником медлительности.

3 голосов
/ 17 июня 2009

Один амперсанд (&, в отличие от &&) выполняет побитовое сравнение. Но сначала вам нужно преобразовать ваши строки в числа с помощью parseInt ().

var map = parseInt("10010", 2); // the 2 tells it to treat the string as binary

var maskForOperation1 = parseInt("10000", 2);
var maskForOperation2 = parseInt("01000", 2);
// ...

if (map & maskForOperation1) { Operation1(); }
if (map & maskForOperation2) { Operation2(); }
// ...
1 голос
/ 17 июня 2009

Битовые операторы, безусловно, будут быстрее, но только линейно и не намного. Вы, вероятно, сэкономите несколько миллисекунд (если только вы не обрабатываете ОГРОМНОЕ количество данных в Javascript, что, скорее всего, в любом случае является плохой идеей).

Вам следует подумать о профилировании другого кода в вашем цикле, чтобы увидеть, что замедляет его больше всего. Какие еще алгоритмы, структуры данных и распределения у вас есть, которые могут использовать рефакторинг?

...