Search code examples
javascriptmathbit-manipulationbitwise-operatorsinteger-arithmetic

Need for a JavaScript/ecma262 ToInt32 algorithm explanation


I'm trying to understand how JS engines convert a JS Number (Float64) to a 32-bit signed integer. I read that one can quickly convert a 64 bit float to a 32 bit signed integer with the bitwise OR like:

-8589934590 | 0 // which gives 2

I can't understand where does the 2 come from. According to the spec, the ToInt32 algorithm does this (the bold text is mine, not the spec's):

  1. Let number be ? ToNumber(argument): -8589934590 is already a Number
  2. If number is NaN, +0, -0, +∞, or -∞, return +0.: No
  3. Let int be the Number value that is the same sign as number and whose magnitude is floor(abs(number)): -8589934590 is already an integer
  4. Let int32bit be int modulo 2³² Since 2³² is positive the result should also be positive. In JS the remainder operator uses the sign of the left operand, so to get a modulo in this case (where -8589934590 is negative), we negate it: let int32bit = 8589934590 % 2**32 // 4294967294 which has 32 bit length 0b11111111111111111111111111111110
  5. If int32bit ≥ 2³¹, return int32bit - 2³²; otherwise return int32bit. int32bit is smaller 2³¹ (since it's negative), so I use int32bit which equals -2 (Even if we consider 0b11111111111111111111111111111110 an unsigned integer, then it's greater 2³¹ and int32bit - 2³² still equals -2

Could someone, please, explain, do I correctly understand the ToInt32 algorithm and the bitwise OR operator?


Solution

  • Your step 4 is wrong. Modulo is defined by the spec as:

    The notation “x modulo y” (y must be finite and nonzero) computes a value k of the same sign as y (or zero) such that abs(k) < abs(y) and x-k = q × y for some integer q.

    So -8589934590 is our x, and 2**32 is our y, from that we also know that k must be positive. If we choose q = -1 we can solve the equation to k = -4294967294. That is however not a valid solution, as k (negative) does not have the same sign as y (positive). If we choose q = -2 instead, we get k = 2.

    So for negative numbers x and positive numbers y, q * y will always have to result in a smaller number than x for k to be positive. Thus if we are transforming that to positive numbers (like you did), we are looking for the larger multiple of the number not the smaller one. E.g. if we take 2 % 3, that'll return 2 (2 - 2 = 3 * 0), whereas -2 modulo 3 will return 1 (-2 -1 = 3 * -1).