other-languages

quoll 2022-01-09T20:12:52.011300Z

Just to vent for a moment… 53-bit integers that can only be (easily) bit-manipulated as 32-bit integers is a really tough paradigm to work around sometimes. Consider this Java:

int x, y;
long carry, ylong = y & 0xFFFFFFFF;
...
long product = ylong * (x & LONG_MASK) + carry;
This takes a pair of 32-bit ints (`x` and y), multiplies them and adds in a carry value. This results in a 64-bit value. Doing the same in JavaScript (and hence, ClojureScript):
function multiplyCarryInt(a, b, carry) {
    const al = 0xFFFF & a
    const ah = a >>> 16;
    const bl = 0xFFFF & b;
    const bh = b >>> 16;

    const blal = bl * al;
    const blah = bl * ah;
    const bhal = bh * al;
    const bhah = bh * ah;

    var p0 = blal + carry;
    var p1 = blah + bhal + (p0 >>> 16);
    return [bhah + (p1 >>> 16), p1 << 16 | (p0 & 0xFFFF)];
}
var [product-high, product-low] = multiplyCarryInt(y, x, carry)
This is gradeschool math. Apparently I can do it with one fewer multiply, but I’m still learning Karatsuba.

quoll 2022-01-09T20:13:29.011900Z

Anyway, I’m slowly making progress. But it feels like JavaScript really doesn’t like numbers

2022-01-09T20:26:06.012400Z

I am guessing this is because its integers are just 64-bit IEEE floats with a 0 mantissa?

quoll 2022-01-09T20:34:39.013Z

Nearly 🙂 Integers are any value where the exponent (not the mantissa) is 0 or more. (Exponents are actually stored as a “biased value”, so exponent=0 is actually stored with the bit pattern corresponding to 1023=0x3FF) When the exponent is zero, then Integers can be stored up to the maximum “Safe” integer value: 9007199254740991 or: 0x1fffffffffffff i.e. 53 bits

quoll 2022-01-09T20:36:36.013300Z

But (and here’s where it gets weird), JavaScript also manages integers greater than this. It does this by increasing the exponent. As a result, it has to “skip” values.

quoll 2022-01-09T20:38:03.013500Z

for (var i = 0; i < 16; i++) console.log( 9007199254740991 + i);
9007199254740991
9007199254740992
9007199254740992
9007199254740994
9007199254740996
9007199254740996
9007199254740996
9007199254740998
9007199254741000
9007199254741000
9007199254741000
9007199254741002
9007199254741004
9007199254741004
9007199254741004
9007199254741006

quoll 2022-01-09T20:40:17.013700Z

Basically, if you’re looking at numbers that large, then you shouldn’t consider them as integers. They’re better thought of as floating point, with a precision that doesn’t extend down to the units

quoll 2022-01-09T20:41:35.013900Z

But JavaScript Number.isInteger(…) returns true on all of those numbers.

quoll 2022-01-09T20:43:10.014100Z

But now that I have all of that off my chest… it DOES handle 32-bit values just fine (sort of). Which means that we can do anything, including 64-bit multiplications. It just takes work.

quoll 2022-01-09T20:43:23.014300Z

I was just venting about the work 🙂

2022-01-09T21:06:51.014500Z

Oh, vent away. The language not having 64-bit integers has led you to working around it to make them out of 32-bit integer ops on half of a 64-bit IEEE float.

2022-01-09T21:08:14.014700Z

I'm sure N-thousand developers have looked at this situation and wondered how much work it would be to add true integer types to JavaScript, and probably gave up after seeing how deep the existing implementation is embedded in the existing libraries out there.

quoll 2022-01-09T21:28:54.014900Z

That “half of a 64-bit IEEE float” is actually where I’m working. As soon as you apply a bit operation, the number is instantly truncated to a signed 32-bit integer.

quoll 2022-01-09T21:30:28.015100Z

For instance, here is a 33-bit integer:

> 0x1ffffffff
8589934591
And here is that same number after applying a no-op bit operation to it:
> 0x1ffffffff | 0
-1

quoll 2022-01-09T21:31:38.015300Z

i.e. it got truncated to the 32-bit value 0xffffffff, and then converted to a signed 32-bit value

quoll 2022-01-09T21:33:45.015500Z

So JavaScript actually has another numerical type: the 32-bit signed int. The problem is that any arithmetic (as opposed to logical) operation on it will promote it to a 53-bit signed int

quoll 2022-01-09T21:59:56.016500Z

actually… I don’t know that it’s stored that way, or if it’s just treated as 32 bit during the operation. The end effect is the same though

2022-01-09T20:26:51.012900Z

A programming language with no true native integer type is just odd to me.