0

Consider the following JAVA statement:

System.out.println(3232235776l & 0xFFFFFFFE);

The output is: 3232235776


When I re-write the statement in JavaScript:

console.log(3232235776 & 0xFFFFFFFE);

The output is: -1062731520


Q. Is there a way to work around this overflow in JavaScript and get the right output?


For the sake of simplicity, I did not post the function I was converting from Java. Here it is. Please assume ipToLong and longToIp as working blackboxes in both Java and JavaScript (i.e. they do the right ip to long int conversion and vice-versa correctly, in both Java and JS, linted and unit tested).

Taken from here: https://stackoverflow.com/a/5032908/504674

Now, can someone help me convert the below Java line to JavaScript correctly?
Specifically: long maskedBase = start & mask;.

Full function to be converted:

public static List<String> range2cidrlist( String startIp, String endIp ) {
    int[] CIDR2MASK = new int[] { 0x00000000, 0x80000000,
        0xC0000000, 0xE0000000, 0xF0000000, 0xF8000000, 0xFC000000,
        0xFE000000, 0xFF000000, 0xFF800000, 0xFFC00000, 0xFFE00000,
        0xFFF00000, 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,
        0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000, 0xFFFFF800,
        0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00, 0xFFFFFF80, 0xFFFFFFC0,
        0xFFFFFFE0, 0xFFFFFFF0, 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE,
        0xFFFFFFFF
    };

    long start = ipToLong(startIp);
    long end = ipToLong(endIp);

    ArrayList<String> pairs = new ArrayList<String>();
    while ( end >= start ) {
        byte maxsize = 32;
        while ( maxsize > 0) {
            long mask = CIDR2MASK[maxsize -1];
            long maskedBase = start & mask;

            if ( maskedBase != start ) {
                break;
            }

            maxsize--;
        }
        double x = Math.log( end - start + 1) / Math.log( 2 );
        byte maxdiff = (byte)( 32 - Math.floor( x ) );
        if ( maxsize < maxdiff) {
            maxsize = maxdiff;
        }
        String ip = longToIp(start);
        pairs.add( ip + "/" + maxsize);
        start += Math.pow( 2, (32 - maxsize) );
    }
    return pairs;
}
6
  • 1
    Some background: JavaScript does not have an int or long type, only Number which is a 64 bit float (like double). The problem is, bitwise operations are done by temporarily converting it to 32bit int and working with this. Commented Oct 4, 2012 at 11:15
  • I understand that, hence I asked for a workaround. Now, is this really impossible in JavaScript? Commented Oct 4, 2012 at 11:16
  • There are some "extende" math libraries available for JavaScript. Syntactically it is not possible but with the use of the functions in those libraries you can obtain the desired results. Commented Oct 4, 2012 at 11:16
  • Link for any of those please? Commented Oct 4, 2012 at 11:18
  • Alternatively, to get rid of mask << 1;, it can be rewritten as mask = mask * 2; Any mathematical equivalent rewrites for the & operator? Commented Oct 4, 2012 at 11:21

2 Answers 2

3

Instead of using & to remove the bit you want, you could subtract it.

long n = 3232235776L;
System.out.println(n - (n & 1)); // instead of 1 you can use ~0xFFFFFFFE

This shouldn't suffer from an overflow in your case.

Sign up to request clarification or add additional context in comments.

8 Comments

It's overflowing in JavaScript. You answer looks Java-related.
The example is Java related just as it is in the question, but the operations shouldn't overflow in JavaScript either.
Q. Is there a way to work around this overflow in JavaScript and get the right output? That is the question.
Oh I see, yes that works. Why not put it into the answer then? The n >> 1 << 1 suffers from the same conversion however.
@phant0m I left converting (n - (n & 1)) into JavaScript as an exercise for the reader. ;)
|
1

Bitwise operators treat their operands as a sequence of 32 bits (zeros and ones)

says the Mozilla documentation.

You start out with a floating point value, it is converted to a 32 bit value. But because it's too big, it will overflow.

I suggest you try the following instead:

var number = 3232235776;
if (number % 2 == 1) {
    number = number - 1;
}

Of course, you could write this more succinctly, but also more cryptic:

var number = 3232235776;
number = number - (number % 2);

That should be semantically equivalent for both positive and negative numbers.

Sign extension

In Java, 0xFFFFFFFE is a 32bit integer representing -2 when ANDing this with a long, it gets converted to a 64bit integer: 0xFFFF_FFFF_FFFF_FFFE, so all this effectively does is clear the last bit, i.e. round down (down, not towards zero).

I'm not sure if that's what you wanted. If it is intended, it's probably not something I would like in my codebase.

No sign extension

Here is the equivalent JavaScript code, if you intended this to happen without sign extension:

var number = 3232235776;
if (number % 2 == 1) {
    number = number - 1;
}
number = number % 0x100000000; // That's 8 zeroes, i.e. keep the last 4 bytes

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.