Reputation:
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;
}
Upvotes: 0
Views: 194
Reputation: 16905
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.
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.
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
Upvotes: 1
Reputation: 533530
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.
Upvotes: 3