I am trying to perform a bitwise not on a 128 bit BigInteger in Java. I have a 128 bit number which has the first 64 bits set to 1 and the last 64 bits set to 0 (I am playing with IPv6 masks).
BigInteger b = new BigInteger(2).pow(64).subtract(BigInteger.ONE).shiftLeft(64);
System.out.println(b.toString(2));
This results in the following, if I output it using base 2:
11111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000
I am trying to flip/reverse all the bits using a bitwise not.
System.out.println(b.not().toString(2));
From my understanding of a bitwise not, I was expecting all the 1's to change to 0's and all the 0's to change to 1's, but I get the following instead:
-11111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000
This also seems to match the documentation of the not() function:
This method returns a negative value if and only if this BigInteger is non-negative
Is it a case of looping through all 128 bits and performing a bitwise not on each separate bit instead?
UPDATE
It probably helps if I try and explain what I was trying to achieve to give some context. I am manipulating IPv6 addresses and was trying to determine if a given IPv6 address was within a subnet or not based on an IPv6 mask.
Based on the responses, I think the following should work:
E.g.
Is 2001:db8:0:0:8:800:200c:417b within 2001:db8::/64?
BigInteger n = new BigInteger(1, InetAddress.getByName("2001:db8::").getAddress());
BigInteger b = BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE).shiftLeft(64);
// First Address in Subnet
BigInteger first = n.and(b);
// Last Address in Subnet (this is where I was having a problem as it was returning a negative number)
BigInteger MASK_128 = BigInteger.ONE.shiftLeft(128).subtract(BigInteger.ONE);
BigInteger last = first.add(b.xor(MASK_128));
// Convert our test IP into BigInteger
BigInteger ip = new BigInteger(1, InetAddress.getByName("2001:db8:0:0:8:800:200c:417b").getAddress());
// Check if IP is >= first and <= last
if ((first.compareTo(ip) <= 0) && (last.compareTo(ip) >= 0)) {
// in subnet
}
As others have pointed out, it's the sign bit that is giving you the result that you don't want.
There are a couple of ways that you can get the inverted bits. For both of them you will need a 128 bit mask value:
private static final BigInteger MASK_128 =
BigInteger.ONE.shiftLeft(128).subtract(BigInteger.ONE);
Then you can either mask the sign bit:
BigInteger b = BigInteger.valueOf(2).pow(64).subtract(BigInteger.ONE).shiftLeft(64);
System.out.println(MASK_128.andNot(b).toString(2));
Or invert directly using xor:
System.out.println(b.xor(MASK_128).toString(2));
I expect the mask value will be useful elsewhere once you start fleshing things out also.
signed byte 64 = 01000000
Invert it
and we get signed byte -65 = 10111111
Sign "minus" is the "not" operator itself:
-1000000 = 0111111
Type this and you see that the values are equal (+1) in absolute
System.out.println(b.toString());
System.out.println(b.not().toString());
Your answer is perfectly correct ,In java everything is in two's compliment:
Convert Decimal to Two's Complement
Convert the number to binary (ignore the sign for now) e.g. 5 is 0101 and -5 is 0101
If the number is a positive number then you are done. e.g. 5 is 0101 in binary using twos complement notation.
Here goes your solution.
If the number is negative then
3.1 find the complement (invert 0's and 1's) e.g. -5 is 0101 so finding the complement is 1010
3.2 Add 1 to the complement 1010 + 1 = 1011. Therefore, -5 in two's complement is 1011.
So, what if you wanted to do 2 + (-3) in binary? 2 + (-3) is -1. What would you have to do if you were using sign magnitude to add these numbers? 0010 + 1101 = ?
Using two's complement consider how easy it would be.
2 = 0010
-3 = 1101
+
-1 = 1111
Converting Two's Complement to Decimal
Converting 1111 to decimal:
The number starts with 1, so it's negative, so we find the complement of 1111, which is 0000.
Add 1 to 0000, and we obtain 0001.
Convert 0001 to decimal, which is 1.
Apply the sign = -1.
In your case
when you do b.not().toString(2) , you will get the response :
-11111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000001
with 1 at the last bit.
Now do the two's compliment and you will get the right answer.
e.g; Flip all the 1's by 0's and vice-versa. after doing that add one to the solution and you will get the solution that you are seeking.
Final solution
00000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111
Use
VALUE = 0xFFFFFFFFFFFFFFFF0000000000000000 - this is patern for bit 1...10...0
VALUE = 0x0000000000000000FFFFFFFFFFFFFFFF - this is patern for bit 0...01...1
Just type by hand 16 x "F" and "0" and remember to add "0x"before each pattern.
Define this values as final.
If You want to generate such values you must do
value += 0x1;
value << 1;
For n times. In your case n is 64.
Related
This question already has answers here:
How are integers cast to bytes in Java?
(8 answers)
Type casting into byte in Java
(6 answers)
Explicit conversion from int to byte in Java
(4 answers)
Closed 4 months ago.
For example of this is my input:
byte x=(byte) 200;
This will be the output:
-56
if this is my input:
short x=(short) 250000;
This will be the output:
-12144
I realize that the output is off because the number does not fit into the datatype, but how can I predict what this output will be in this case? In my computer science exam this my be one of the questions and I do not understand why exactly 200 changes to -56 and so one.
I realize that the output is off because the number does not fit into the datatype, but how can I predict what this output will be in this case? In my computer science exam this my be one of the questions and I do not understand why exactly 200 changes to -56 and so one.
The relevant aspects are what overflow looks like, and how the bits that represent the underlying data are treated.
Computers are all bits, grouped together in groups of 8; a group of 8 bits is called a byte.
byte b = 5; for example, is stored in memory as 0000 0101.
Bits can be 0. Or 1. That's it. That's where it ends. And everything is, in the end, bits. This means: That - is not a thing. Computers do not know what - is and cannot store it. We need to write code and agree on some sort of meaning to represent them.
2's complement
So what's -5 in bits? It's 1111 1011. Which seems bizarre. But it's how it works. If you write: byte b = -5;, then b will contain 1111 1011. It is because javac made that happen. Similarly, if you then call System.out.println(b), then the println method gets the bit sequence 1111 1011. Why does the println method decide to print a - symbol and then a 5 symbol? Because it's programmed that way: We all are in agreement that 1111 1011 is -5. So why is that?
Because of a really cool property - signed/unsigned irrelevancy.
The rule is 2's complement: To switch the sign (i.e. turn 5, which is 0000 0101 into -5 which is 1111 1011), you flip every bit, and then add 1 to the end result. Try it with 0000 0101 - and you'll see it's 1111 1011. This algorithm is reversible - apply the same algorithm (flip every bit, then add 1) and you can turn -5 into 5.
This 2's complement thing has 2 great advantages:
There is only one 0 value. If we just flipped all bits, we'd have both 1111 1111 and 0000 0000 both representing some form of 0. In basic math, there's no such thing as 'negative 0' - it's the same as positive 0. Similarly if we just decided the first bit is the sign and the remaining 7 bits are the number, then we'd have both 1000 0000 and 0000 0000 both being 0, which is annoying and inefficient, why waste 2 different bit sequences on the same number?
plus and minus are sign-mode independent. The computer doesn't have to KNOW whether we are doing the 2's complement thing or not. Take the bit sequence 1111 1011. If we treat that as unsigned bits, then that is 251 (it's 128 + 64 + 32 + 16 + 8 + 2 + 1). If we treat that as a signed number, then the first bit is 1, so the thing is negative: We apply 2's complement and figure out that it is -5. So, is it -5 or 251? It's both, at once! Depends on the human/code that interprets this bit sequence which one it is. So how could the computer possibly do a + b given this? The weird answer is: It doesn't matter - because the math works out the same way. 251 - 10 is 241. -5 - 10 is -15. -15 and 241 are the exact same bit sequence.
Overflow
A byte is 8 bits, and there are 256 different sequences of bits, and then you have listed each and every possible variant. (2^8 = 256. Hence, a 16-bit number can be used to convey 65536 different things, because 2^16 is 65536, and so on). So, given that bytes are 8 bits and we decreed they are signed, and 2's complement signed, that means that the smallest number you can send with it is -128, which in bits is 1000 0000 (use 2's complement to check my work), and +127, which in bits is 0111 1111. So what happens if you add 1 to 127? That'd seemingly be +128 except that's not storable in 8 bits if we decree that we interpret these bits as 2's complement signed (which java does). What happens? The bits 'roll over'. We just add 1 as normal, which turns 0111 1111 into 1000 0000 which is -128:
byte b = 127;
b = (byte)(b + 1);
System.out.println(b); // prints -128
Imagine the number line - stretching out into infinity on both ends, from -infinite to +infinite. That's the usual way math works. Computers (or rather, int, long, etc) do not work like that. Instead of a line, it is a circle. Take your infinite number line and take some scissors, and snip that number line at -128 (because a 2's comp signed byte cannot represent -129 or anything else below -128), and at +127 (because our byte cannot represent 128 or anything above it).
And now tape the 2 cut ends together.
That's the number line. What's 'to the right' of 125? 126 - that's what +1 means: Move one to the right on the number line.
What's 'to the right' of +127? Why, -128. Because we taped it together.
Similarly, -127 - 5 is +123. '-5' is 'move 5 places to the left on the number line (or rather, number circle)'. Going in 1 decrements:
-127 (we start here)
-128 (-127 -1)
+127 (-127 -2)
+126 (-127 -3)
+125 (-127 -4)
+124 (-127 -5)
Hence, 124.
Same math applies to short (-32768 to +32767), char (which is really a 16-bit unsigned number - so 0 to 65535), int (-2147483648 to +2147483647), and even long (-2^63 to +2^63-1 - those get a little large).
short x = 32765;
x += 5;
System.out.println(x); // prints -32766.
I am working on a file reader and came into a problem when trying to read a short. In short (punintended), java is converting a two bytes I'm using to make the short into an int to do bitwise operations and is converting it in a way to keep the same value. I need to convert the byte into an int in a way that would preserve its value so the bits stayed the same.
example of what's happening:
byte number = -1; //-1
int otherNumber = 1;
number | otherNumber; // -1
example of what I want:
byte number = -1; //-1
int otherNumber = 1;
number | otherNumber; // 129
This can be done pretty easily with some bit magic.
I'm sure you're aware that a short is 16 bits (2 bytes) and an int is 32 bits (4 bytes). So, between an integer and a short, there is a two-byte difference. Now, for positive numbers, copying the value of a short to an int is effectively copying the binary data, however, as you've pointed out, this is not the case for negative numbers.
Now let's look at how negative numbers are represented in binary. It's a bit confusing, so I'll try to keep it simple. Modern systems use what's called the two's compliment to store negative numbers. Basically all this means is that the very first bit in the set of bytes representing the number determines whether or not it's negative. For mathematical purposes, the rest of the bits are also inverted and offset 1 bit to the right (since you can't have negative 0). For example, 2 as a short would be represented as 0000 0000 0000 0010, while -2 would be represented as 1111 1111 1111 1110. Now, since the bytes are inverted in a negative number, this means that -2 in int form is the same but with 2 more bytes (16 bits) at the beginning that are all set to 1.
So, in order to combat this, all we need to do is change the extra 1s to 0s. This can be done by simply using the bitwise and operator. This operator goes through each bit and checks if the bits at each position in each operand are a 1 or a 0. If they're both 1, the bit is flipped to a 0. If not, nothing happens.
Now, with this knowledge, all we need to do is create another integer where the first two bytes are all 1. This is fairly simple to do using hexidecimal literals. Since they are an integer by default, we simply need to use this to get four bytes of 1s. With a single byte, if you were to set every bit to 1, the max value you can get is 255. 255 in hex is 0xFF, so 2 bytes would be 0xFFFF. Pretty simple, now you just need to apply it.
Here is an example that does exactly that:
short a = -2;
int b = a & 0xFFFF;
You could also use Short.toUnsignedInt(), but where's the fun in that? 😉
This question already has answers here:
java byte data type
(3 answers)
Closed 8 years ago.
since english isn't my main language and i've didn't find any pointers as to how to manually calculate the new number.
Example:
byte b = (byte) 720;
System.out.println(b); // -48
I know that most primary data types use the two complement.
Byte value ranges from -128 to 127, so it's expected to round the number down to something that fits in byte.
The Question is how do i manually calculate the -48 of the typecasted 720? I've read that i have to convert it to two complement, so taking the binary number, searching from right to left for the first one and then inverting all others and since byte only has 8 bits, take the first 8 bits. But that didn't quite work for me, it would be helpful if you would tell me how to calculate a typecasted number that doesn't fit into byte. Thanks for reading! :)
The binary representation of 702 is
10 1101 0000
Get rid of everything except the last 8 bits (because that's what fits into a byte).
1101 0000
Because of the leading 1, get the complement
0010 1111
and add 1
0011 0000
and negate the value. Gives -48.
In Java, integral types are always 2's complement. Section 4.2 of the JLS states:
The integral types are byte, short, int, and long, whose values are 8-bit, 16-bit, 32-bit and 64-bit signed two's-complement integers
You can mask out the least significant 8 bits.
int value = 720;
value &= 0xFF;
But that leaves a number in the range 0-255. Numbers higher than 127 represent negative numbers for bytes.
if (value > Byte.MAX_VALUE)
value -= 1 << 8;
This manually yields the -48 that the (byte) cast yields.
First what happens is the value (in binary) is truncated.
720 binary is 0b1011010000
We can only fit 8 bits 0b11010000
first digit 1, so the value is negative.
2's compliment gives you -48.
This is close to redundant with the answer posted by rgettman, but since you inquired about the two's complement, here is "manually" taking the 2's complement, rather than simply subtracting 256 as in that answer.
To mask the integer down to the bits that will be considered for a byte, combine it bitwise with 11111111.
int i = 720;
int x = i & 0xFF;
Then to take the two's complement:
if (x >> 7 == 1) {
x = -1 * ((x ^ 0xFF) + 1);
}
System.out.println(x);
byte x=3;
x=(byte)~x;
System.out.println(x);
I was confused between the output being 4 or 0 but the output is coming to be -4.
How is that ??
It's simple !!
~a = -a - 1
Since the value of a = 3, the answer must be -4. You can check with other values too.
On a byte 3 is represented as 00000011. Then ~3 is 11111100 which is a negative number (starts with 1).
See the official docs:
The unary bitwise complement operator "~" inverts a bit pattern; it
can be applied to any of the integral types, making every "0" a "1"
and every "1" a "0". For example, a byte contains 8 bits; applying
this operator to a value whose bit pattern is "00000000" would change
its pattern to "11111111".
What is 3 in binary? It's 0000 0011.
What's ~3? It's 11111100, which is -4 (Two's complement).
Note, ~ is not an negation, it's an operator.
bit 3 = 0000 0011
x = 3
~x = 1111 1100
the ~ is the bitwise not. So when the first value in the bit string is a 1 it is a negative
~ is reversing a Bit operator.
Bit reversal consists of reversing the value of a bit. If the box contains 1, you can reverse it to 0. If it contains 0, you can reverse it to 1. To support this operation, the Java language provides the bitwise negation operator represented with the ~ symbol.
3 --> 00000011
~3 --> 11111100
As it's a 2's complement number, the first bit being one means that it's a negative number.
11111100=-4
To verify see below:
00000011 <- reversing
+ 1<- adding 1
00000100 =4
In java when I say Integer i = Math.abs(Integer.MIN_VALUE). I get the same value as the answer,which means i contains Integer.MIN_VALUE.
I have verified the same in C++ as well.
Why this behavior?
Read this in Effective Java by Joshua Bloch.
I found the answer for this question and here is the explanation:
Computers work with binary arithmentic, the logic of Math.abs in java or the absolute function in any language is like below:
if(num >= 0)
return num;
else
return (2's complement of the num);
Note : How to find 2's complement
For a given number, we find it's 1's complement first and then add 1 to it. For e.g.
Consider our number to be 10101
1's complement= 01010
2's complement= 01011 (added 1 to the 1`s complement)
Now, for the sake of making it easy and clear, let us say that our Integer(signed) size is 3 bit, then here is the possible list of numbers which can be produced using the four bits:
000 --> 0 (0)
001 --> 1 (1)
010 --> 2 (2)
011 --> 3 (3)
100 --> 4 (-4)
101 --> 5 (-3)
110 --> 6 (-2)
111 --> 7 (-1)
Now that this is signed, it means half of the numbers are negative and the other half are positive(The negative numbers are the ones with the first bit 1). Let us start from 000 and try to find its negative number, it would be the two's complement of 000.
2's complement of `000` = 1 + `111` = `000`
2's complement of `001` = 1 + `110` = `111`
2's complement of `010` = 1 + `101` = `110`
2's complement of `011` = 1 + `100` = `101`
2's complement of `100` = 1 + `011` = `100`
2's complement of `101` = 1 + `010` = `011`
2's complement of `110` = 1 + `001` = `010`
2's complement of `111` = 1 + `000` = `001`
From the above demonstration, we find that 2's complement of 111(-1) is 001(1), similarly 2's complement of 110(-2) is 010(2), 2's complement of 101(-3) is 011(3) and 2's complement of 100(-4) is 100(-4) and as we can see that -4 is the smallest negative number possible using 3 bits.
This is the reason why absolute of Integer.MIN_VALUE is Integer.MIN_VALUE.
There is an inherent asymmetry that is the root cause of this effect. The number of 32-bit bit patterns is even. One of those patterns is used for zero. That leaves an odd number of non-zero values. The number of positive values and the number of negative values cannot be equal because their sum is odd.
In the 2's complement representation used for Java integers, the number of negative numbers is one greater than the number of positive numbers. Each negative number other than Integer.MIN_VALUE corresponds to a positive number that is both its negation and its absolute value. Integer.MIN_VALUE is left over, with no corresponding positive int. Math.abs and negation map it to itself.
Why this behavior?
It is a mathematical consequence of the choice of representation used in all modern computers.
Here's an informal proof of why it has to be that way.
A signed binary number representation with N bits has 2N possible values; i.e. a set integers with an even number of elements.
Remove zero from the set. The set is now has an odd number of elements.
Now remove all pairs of numbers of the form {n, -n}. Each time we remove a pair of numbers, the set still contains an odd number of elements.
We are now left with a set that contains an odd number of integers for which n is in the set, but -n is not in the set. Since the set size is odd, it cannot be empty; i.e. there is at least one number with this property.
In the representations specified by Java (and indeed used all other practical languages), integer types have 2N-1 negative values and 2N-1 - 1 values greater than zero. The value that has the strange property is MIN_VALUE. This representation is called two's complement.
Strictly speaking, an integer representation doesn't have to have this anomaly:
It is possible to have two zeros (-0 and +0); e.g. signed magnitude or one's complement representations. (This invalidates step 2 of the proof: there are now 2 zeros to remove.)
It is possible to exclude -2N-1; i.e. make it an illegal value. (This invalidates step 1 of the proof: the initial set now has an odd number of values.)
It is possible to specify integer arithmetic so that (for example) negating MIN_VALUE raises an exception. For instance Math.abs(Integer.MIN_VALUE) would throw an exception.
However, all of these things have significant performance implications, especially since modern computer hardware only supports twos-complement arithmetic natively. They also have issues in relation to writing reliable integer codes ...
Math.abs(int) docs says If the argument is negative, the negation of the argument is returned. JLS 15.15.4. Unary Minus Operator says For all integer values x, -x equals (~x)+1.
-Integer.MIN_VALUE = ~Integer.MIN_VALUE + 1 = ~0x80000000 + 1 = 0x7FFFFFFF + 1 = 0x80000000 = Integer.MIN_VALUE
You might expect that absolute value of Integer.MIN_VALUE would be Integer.MAX_VALUE + 1, but this value is out of primitive int size. And Integer.MAX_VALUE + 1 is Integer.MIN_VALUE again. That's all.
This is because of the way two's-complement number systems work. Integer.MIN_VALUE corresponds to 0x80000000. The standard way to negate it is to take its ones' complement (0x7FFFFFFF in this case) and add 1, and in this case it would overflow back to 0x80000000.