5

Often, for programming languages implementations, it is desirable to tag numbers using bitwise operators. In C, you could tag a double by using an union:

typedef union Tag_ { double d; long long i; } Tag;
double tag(double x){ Tag tmp; tmp.d = x; tmp.i |= 1; return tmp.d; };
double isTagged(double x){ Tag tmp; tmp.d = x; return tmp&1; };

What is a way to mimic this behavior on JavaScript? Using bitwise operators is ruled out, since it converts the doubles to Uint32s. I need a mathematical solution.

MaiaVictor
  • 51,090
  • 44
  • 144
  • 286
  • Why would you want to do that in JavaScript? What is your actual use case? – Bergi Oct 16 '14 at 13:46
  • 1
    Compiling a Scheme-like language to JavaScript. There are no tagged unions, so using the bits on the double to simulate it would certainly be much faster than creating objects, since it would allow, for example, using typed arrays for my stacks. – MaiaVictor Oct 16 '14 at 20:15
  • 2
    I see. I already wanted to propose to use a typed array, as you can just use an `Uint32Array` and a `Float64Array` on the *same* buffer; however I thought that creating those three objects would be no gain over the "non-unioned" object literal. But if you are using them anyway… – Bergi Oct 16 '14 at 23:27
  • 1
    Hmm that actually makes a lot of sense. How can I create separated views of the same array? AFAIK, `new Float64Array(foo)` creates a new copy. Edit: NVM, but what about the different sizes? That is, there is no "Uint64Array"... – MaiaVictor Oct 17 '14 at 20:17
  • Yes, [there is no `Uint64Array`](http://stackoverflow.com/q/6041124/1048572), because it's not ([yet?](https://esdiscuss.org/topic/proposal-for-new-floating-point-and-integer-data-types)) possible to have 64bit integer values in JS. – Bergi Oct 18 '14 at 15:02

1 Answers1

1

This has not received an answer, perhaps you found one? If not:

Let me start off with the question in your comments, as it sounds like solving that question in the end solves the original question.

How can I create separated views of the same array?

This is essentially Bergi's proposal from the comments, slightly modified. It answers the How.

When you create an ArrayBuffer you can access the underlying array of bytes from multiple typed Arrays by passing that array buffer as an initial parameter. I've found JavaScripture -- ArrayBuffer to be quite helpful in the past with TypedArrays. So the following reserves 8 bytes in memory and accesses it as both a 64-bit float and 8 byte ints.

var myBuff = new ArrayBuffer(8);
var myU8Arr = new Uint8Array(myBuff);
var myFloat64Arr = new Float64Array(myBuff);

so if you say set the first byte in the buffer to 1, and then access that value from the float you will get a narly float:

myFloat64Arr[0] = 10000;
console.log(myFloat64Arr[0])//prints 0;
myU8Arr[7] |= 128;//sets sign bit of IEEE 754 Double-precision float.
//setting the sign because it's more straightforward than if another
//bit was to be set. 
console.log(myFloat64Arr[0]);//prints -10000 ... all dependent on system endianess

So, now that the question from the comments has been answered:

How can I use the least significant bit to tag my numbers?

Directly addressing the question; I don't see a problem with using the Typed Arrays. We can bitwise on the underlying bytes in the underlying Array Buffer without worrying that the byte will be turned into a 64-bit float and mess things over.

Sticking with your "stack" of floats will get you the added performance. Simple create the ArrayBuffer and then both the Uint8Array and Float64Array instead of an array of numbers (or an array of Tags). Otherwise you could make a Tag function with an ArrayBuffer, Uint8Array and Float64Array attributes in it's scope and then create new instances of it for each number... but this doesn't save you much of anything in the javascript realm. Might as well polyfill in a tag attribute/function on variables and the Number prototype if you're going to go that route of creating Tag-like structures. It won't give you the storage performance, but would at least keep the tag coupled with each number.

Because of endianess and there being no 64-bit integer array you'll need to handle the index of the LSB slightly differently. Check the endianess and set a global variable, or whatever other way you see most fit. on a little endian system:

var globalMyBuff = new ArrayBuffer(n);//n is your number of floats * 8 (8 bytes per float)
var globalMyU8Arr = new Uint8Array(globalMyBuff);
var globalMyFloat64Arr = new Float64Array(globalMyBuff);

//Load your floats into globalMyFloat64Arr

//tag a float at index when desired
function tag(index){
    //"index << 3 " is essentially the same as "index * 8", but faster
    //since it will get compiled into a shift op
    myU8Arr[index << 3] |= 1;//sets the LSB
}
//check tag at index when desired
function isTagged(index){
    //"index << 3 " is essentially the same as "index * 8", but faster
    //since it will get compiled into a shift op
    return (myU8Arr[index << 3] & 1) == 1;//checks LSB
}
Community
  • 1
  • 1
Arthur Weborg
  • 8,280
  • 5
  • 30
  • 67
  • 1
    Unfortunately, using an array was way, way too slow on my benchmarks. It is probably the most flexible solution, though. For my specific case, I had better results using IEEE 754 arithmetic to manipulate the bits on floats, since JS does that fast. Thank you! – MaiaVictor Jun 07 '15 at 18:42
  • I figured you had already solved this, but saw the question and realized I knew an answer :) glad to hear you had a solution and that you went with what was best for your case! – Arthur Weborg Jun 07 '15 at 23:21
  • 1
    Yes, I know! Thank you very much. I might post my own solution too, but I'm in a tight schedule right now, so that will have to wait... – MaiaVictor Jun 07 '15 at 23:35