Why does System.out.println(-1<<32) display -1 in Java? Is there any root cause? I hope somebody can explain!
In Java (and JavaScript), a << b automatically wraps b modulo the bit length of the numeric type. You're doing it with an int, which is 32 bits, and 32 % 32 = 0, therefore, no change. You can always just check for a b of more than (bit length - 1) and automatically set to zero instead of shifting.
Related
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? 😉
C++ allows you to combine two integer comparisons in one for range checking, like
(unsigned)X < (unsigned)Upper
which returns true when
0 <= X < Upper
The Java language has no unsigned type. Do you see a way to obtain the same effect, using a single comparison and not too much overhead ?
Update:
From a comment by #Bathsheba, the char type is unsigned 16 bits and will be fit for my purpose, as my integers are actually in the range of shorts.
The question remains open for plain ints.
Possibly something in the line of (X | (Upper - 1 - X)) >= 0, which allows a range of 30 bits.
If you want a datatype in Java that is able to hold the range of values that an unsigned 32-bit int can hold, then you need long. You can bit-mask with 32 one-bits to convert the signed int that is possibly negative to a surely-positive long value.
(x & 0xffffffffL) < upper
// ^
// Implicit conversion to long (of both arguments)
Of course the 64-bit "and" and the 64-bit comparison will take some extra time but probably less than the pipe line breaks.
I am getting a strange error while attempting to use a java signed long integer to store 64 bits of boolean data. The values are being set and tested correctly, except for every bit where (bits & (1 << n)) >0 is true, a value of n 32 higher is also inexplicably true (nonzero).
I am thinking this is a result of rollover somehow, but i am not familiar with how java handles sign bits and rollover internally. this same sort of operation has worked fine in other languages with only signed integer types.
Pseudocode for my bit operations:
// this is for manipulating minecraft world chunks directly, if anyone is wondering what the point is.
// there is really no higher-level alternative that wont use vast amounts of memory and time.
long[][][] bits = new long[16][16][4]; // an array of long bitfields, each representing 64 blocks along Y-axis
// 16x16x(4x64) is 65536 blocks, or one chunk
// bits[ column-x ][ column-z ][ slices-y ] - fairly basic format
// set a bit (this all works fine, i have tested the results)
long nb = ( (long)1 << (b.getY()%64) ); // the new bit to be set.
//(a % b + b) % b fixes issues with java modulus giving negative results for negative values of a
bits[(b.getX()%16 + 16)%16][(b.getZ()%16+16)%16][b.getY()/64] |= nb;
// set the relighting bit for the block
// This is the bug.
//Loops through n=63 to n=0
b = one of the longs from bits[][][]
n=64;
while(--n>-1)
if( (b & (1<<n)) > 0 )....
// this evaluates correctly to nonzero for the expected bit, but also for every value of n 32 higher than each expected one.
// IE; if the 4th bit is set, b & (1<<3) is nonzero, but b & (1<<35) also tests nonzero. i have debugged the bitmasks before the operation and confirmed that only the correct bit is set.
// the resulting value of b & (1<<n) is the same for the correct value and for the value 32 bits farther along.
In the if statement towards the end of the code
(1<<n)
needs to be
(1L<<n)
I have an int, and I would like to get the 19 most significant bits in java. I tried all sorts of methods, none of them work.
Can someone please help me?
Adding to Bram's answer, you don't even need the AND if you use unsigned shift.
myInt >>> 13; will give you the 19MSB (although they're now situated in the lowest bits).
From the 32 bit int, you want to keep the 19 most significant, so discard the 13 least; then you shift right by 13 bits, but have to get rid of the possible sign extension, by anding with a 19 bit pattern:
(myint >> 13) & 0x7ffff
Integer is of 4 byte i.e. 4*8 = 32 bits. So if you want to get 19th bit, you may want to try something like:
if (myint & 0X00002000 >> 19 == 1) {
//do something
}
I have a 3 byte signed number that I need to determine the value of in Java. I believe it is signed with one's complement but I'm not 100% sure (I haven't studied this stuff in more than 10 years and the documentation of my problem isn't super clear). I think the problem I'm having is Java does everything in two's complement. I have a specific example to show:
The original 3-byte number: 0xEE1B17
Parsed as an integer (Integer.parseInt(s, 16)) this becomes: 15604503
If I do a simple bit flip (~) of this I get (I think) a two's complement representation: -15604504
But the value I should be getting is: -1172713
What I think is happening is I'm getting the two's complement of the entire int and not just the 3 bytes of the int, but I don't know how to fix this.
What I have been able to do is convert the integer to a binary string (Integer.toBinaryString()) and then manually "flip" all of the 0s to 1s and vice-versa. When then parsing this integer (Integer.parseInt(s, 16)) I get 1172712 which is very close. In all of the other examples I need to always add 1 to the result to get the answer.
Can anyone diagnose what type of signed number encoding is being used here and if there is a solution other than manually flipping every character of a string? I feel like there must be a much more elegant way to do this.
EDIT: All of the responders have helped in different ways, but my general question was how to flip a 3-byte number and #louis-wasserman answered this and answered first so I'm marking him as the solution. Thanks to everyone for the help!
If you want to flip the low three bytes of a Java int, then you just do ^ 0x00FFFFFF.
0xFFEE1B17 is -1172713
You must only add the leading byte. FF if the highest bit of the 3-byte value is set and 00 otherwise.
A method which converts your 3-byte value to a proper intcould look like this:
if(byte3val>7FFFFF)
return byte3val| 0xFF000000;
else
return byte3val;
Negative signed numbers are defined so that a + (-a) = 0. So it means that all bits are flipped and then 1 added. See Two's complement. You can check that the condition is satisfied by this process by thinking what happens when you add a + ~a + 1.
You can recognize that a number is negative by its most significant bit. So if you need to convert a signed 3-byte number into a 4-byte number, you can do it by checking the bit and if it's set, set also the bits of the fourth byte:
if ((a & 0x800000) != 0)
a = a | 0xff000000;
You can do it also in a single expression, which will most likely perform better, because there is no branching in the computation (branching doesn't play well with pipelining in current CPUs):
a = (0xfffffe << a) >> a;
Here << and >> perform byte shifts. First we shift the number 8 bits to the right (so now it occupies the 3 "upper" bytes instead of the 3 "lower" ones), and then shift it back. The trick is that >> is so-called Arithmetic shift also known as signed shift. copies the most significant bit to all bits that are made vacant by the operation. This is exactly to keep the sign of the number. Indeed:
(0x1ffffe << 8) >> 8 -> 2097150
(0xfffffe << 8) >> 8 -> -2
Just note that java also has a unsigned right shift operator >>>. For more information, see Java Tutorial: Bitwise and Bit Shift Operators.