Porting '&' operator from Java to Javascript: Overflow issues

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:

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;
}

2 Answers

  1. Lee- Reply

    2019-11-14

    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.

  2. Leo- Reply

    2019-11-14

    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
    

Leave a Reply

Your email address will not be published. Required fields are marked *

You can use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>