Unable to pass long to JavaScript (only signed int)

David Buff's icon

May be this issue is known...

Inside a JS object, instruction post(Math.pow(2, 33)) output the correct value 8589934592. That proves that the internal integer representation in javascript (inside JS object) is long.

But passing 2^33 (value 8589934592) from Max to JS object and then post it show that the value has been truncated. The fact that 2^31 works but not 2^32 show that the value passed is a signed 32 bits integer.

... it's sad not exploiting all the possible range of integer representation, and loose a part only in transfer from Max to JS Object... probably problem is somewhere in Max API...

regards!

yaniki's icon

I faced this problem some time ago and I made simple workaround: it is possible to convert long into string, send this string to the JS object, and parse as a number back inside the script. Not super-elegant, but works.

David Buff's icon

The internal Max API generate a string table when we pass messages with strings (the internal gensym() method). So I wonder if passing numbers as strings, very frequently or in large quantity... will generate a signifiant memory leak because of the gensym() table...

May be a little more elegant, the solution I use is to split the long into 2 int32 with binary offset and mask. Something like:

In MAX (or in my case in C inside a Max Object written with Max API):
value = 2^53-1; // very big number (long), the MAX_SAFE_INTEGER in JavaScript specifications
v1 = value>>24; // offset the most significant bits, to keep it in a single 32 bit integer
v2 = value&0xFFFFFF; // 0xFFFFFF = 2^24-1 ... equivalent mask of >>24 offset, keep less significant bits

In JS (pass v1 and v2 into JavaScript in a single function like ):
function bigInt(v1, v2) {
    var value = v1*0x1000000+v2; // (v1*0x1000000) is same as (v1<<24)
    post("JS value:"+value+" for v1:"+v1+" v2:"+v2+"\n");
}

Note 1: I don't know why, but v1<<24 doesn't work in JS... so I replace it by *0x1000000
Note 2: 2^53-1 is really the JS limit, testing 2^53 and 2^53+1 proves it. It indicates that JS internal number representation is a double (64 bits float precision)... see IEEE 754 about float encoding (mantisse of 52 bits for double)
Note 3: if 2^53 is max, then >>24 is suffisant (24 is the half of this 53 bit size)... in some case, bigger offset as >>30 could be needed... remember over >>31 there is sign problem with 32 bits integer (bit 32 is reserved for sign)

yaniki's icon

It's the most epic workaround I ever seen.

Joshua Kit Clayton's icon

@David, thanks for pointing this out. Totally slipped by my radar.

I've fixed this for the next version, but for now the easiest thing to do is pass the integer through a float object if an argument to a message. If passed without a message prefix, that simple float workaround won't work unfortunately.

I appreciate your hi/lo word workaround. Takes me back to writing the hi-res MSP objects which did similar to pass near double precision floating point audio signals as two single precision floating point signals.

David Buff's icon

Happy to help :o)
Max is a so nice soft!