3

I have a class representing bits and it uses ArrayBuffers to store the binary data. I'm trying to figure out if there is a faster method to perform a xor between two ArrayBuffers.

Note The length of the ArrayBuffers are usually less than 10 bytes. But since the xor operation is performed millions, if not billions of times, every millisecond saved matters.

// my current/simple method
// assume 'buf1', 'buf2' & 'result' are ArrayBuffers
for (var i=0; i<result.length; i++) {
  result[i] = buf1[i] ^ buf2[i];
}

Note Seeking solution executable both locally and on browser.

EyuelDK
  • 3,029
  • 2
  • 19
  • 27
  • Parallel.js's`map`? – Federico klez Culloca Dec 19 '17 at 16:41
  • @FedericoklezCulloca I thought that but isn't the overhead of spawning worker threads/process each xor of less than a 10 bytes worth it? – EyuelDK Dec 19 '17 at 16:44
  • Write a c / rust binding. I dont think that this can be made faster in js ( except asm.js or parallel threads) – Jonas Wilms Dec 19 '17 at 16:44
  • @JonasW. Updated my question to specify "pure javascript solution." Thanks for your input. – EyuelDK Dec 19 '17 at 16:46
  • 1
    If the datasets are that small, I think your current solution should be more than adequate. My suggestion is to measure the performance both with your solution and with Parallel and see for yourself which solution is better in your case. – Federico klez Culloca Dec 19 '17 at 16:47
  • Do you count WebAssembly as javascript? It runs in the browser too but is actually not js – Jonas Wilms Dec 19 '17 at 16:50
  • @JonasW. Interesting... I don't know about WebAssembly, but please do tell. I'll edit my question again to specify browser compatibility – EyuelDK Dec 19 '17 at 16:53
  • @FedericoklezCulloca is right. BUT if you find that real use yields really big arrays (at least some thousands of bytes) could be interesting to make use of the graphics 2D acceleration (if available) using a canvas, so you are sending the hard "calculation work" to a -probably- parallellized GPU. – miguel-svq Dec 19 '17 at 16:56
  • [You can find more about `WebAssembly` here](https://developer.mozilla.org/en-US/docs/WebAssembly/Concepts) – Jonas Wilms Dec 19 '17 at 16:57

1 Answers1

4

I know of 4 ways to calculate XOR:

  • the native ^ operator
  • (n1+n2)%2
  • n1+n2-2*n1*n2
  • use a preset array: xor=[[0,1],[1,0]]

I ran the following code, you can see the results for yourself:

buf1=new Array(10000).fill(1).map((x)=>Math.floor(Math.random()*2));
buf2=new Array(10000).fill(1).map((x)=>Math.floor(Math.random()*2));

console.time('go');
for (let i=0;i<10000;i++) r=buf1[i]^buf2[i];
console.timeEnd('go');

console.time('go');
for (let i=0;i<10000;i++) r=(buf1[i]+buf2[i])%2;
console.timeEnd('go');

console.time('go');
for (let i=0;i<10000;i++) r=buf1[i]+buf2[i]-2*buf1[i]*buf2[i];
console.timeEnd('go');

xor=[[0,1],[1,0]];
console.time('go');
for (let i=0;i<10000;i++) r=xor[buf1[i]][buf2[i]];
console.timeEnd('go');

All the methods seem to give similar results.

JMP
  • 4,417
  • 17
  • 30
  • 41
  • I am intrigued by your use of a preset array - very interesting results. I'll mark it as an answer unless a better solution comes. May I ask if it is possible to convert the ArrayBuffer into a Number and perform xor? Sort of like how python allows you to change `bytes` to `int` ? – EyuelDK Dec 19 '17 at 18:53
  • it might be, but I don't think you'll gain much. Each bit still needs to be XOR'd, and there is no way around this. – JMP Dec 19 '17 at 18:56
  • 1
    Is it not possible to `xor` 2-4 bytes at a time? Taking advantage of 32-64 bit machines' registers? – EyuelDK Dec 19 '17 at 18:59
  • [XOR](https://en.wikipedia.org/wiki/XOR_gate) is a logic gate. it takes two inputs and returns a single output – JMP Dec 19 '17 at 19:04
  • @EyuelDK yes, a^b is most certainly compiles down to the xor assembly instruction and doing the XOR 4 bytes at a time. it's not doing a xor bit by bit in a loop :) There's a XOR logic gate and 32 of those are used when doing an assembly XOR on 32 bit registers (not really relevant to the question though!). – Olivier Lalonde Sep 25 '19 at 20:08
  • Oh I just realized @JMP answer is using arrays of 1s and 0s, not sure why you accepted it :O FWIW, your own answer was probably a loooot faster and memory efficient. You might want to try https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/xor though. – Olivier Lalonde Sep 25 '19 at 20:17