thank you in advance for this basic question.
I am going through a tutorial and I see this line.
int a = (n & 8) / 8
This is supposed to identify whether the fourth bit from the right is a binary representation of 0 or 1. I understand the concept of bits etc, but I do not understand what mathematical equation (if any) this represents.
Would anyone care to explain how this would be written in a mathematical equation? Also, please let me know if i am missing anything else in my understanding of this line. Thank you.
The expression ( n & 8 )
does Logical And of n with 1000 binary.
So that gets the 4th bit from right.
then dividing that by 8, shifts the value right 3 binary places. I.e. it moves the 4th bit to the rightmost place.
That is more clearly expressed as " >> 3"
So your overall expression would be something like:
(n AND 1000 ) >> 3
And that leaves the 4th bit of N in a temporary variable, as bit 0 (rightmost bit).
All the other bits will be zero because of the AND.
8 in decimal is 1000 in binary
so if you do bitwise AND with any number
n & 8
it will stay 8 only if the 4th bit is 1 and
if you divide it by 8 again it will return 1, zero otherwise
For example
for 9 (1001)
9 & 8
would be
1001
& 1000
------
1000
Now for the case where forth bit is 0
for 7 (0111)
7 & 8
would be
0111
& 1000
-----
0000
int a = (n & 8) / 8;
The n & 8 applys a logical AND mask to the 4th bit of n;
n: 11001010 // example value
8: 00001000
result: 00001000
Dividing that number by 8 brings the result to the lowest bit :
result: 00000001
Dividing a number by 2^n shifts the numbers n bits to the right (in the same way that multiplying by 2^n shifts bits to the left).
The result is assigned to variable a, which now contains 0 or 1, depending on the value of the 4th bit.
Bitwise operator works on bits and performs bit-by-bit operation. Assume if a = 60; and b = 13; now in binary format they will be as follows:
a = 0011 1100
b = 0000 1101
a&b=0000 1100
then a&b is also an integer which is further divided by 8 in your example.
Related
Is there an equivalent function for Math.signum(double) or Math.signum(float) in Java for other primitive numbers like int or long. I don't want to write code like
int sign = (int) Math.signum((double) intValue);
when there is a better alternative.
You can use it this way:
Integer.signum(int i) and Long.signum(long l)
Link to javadoc: https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#signum-int-
Just an addendum of some implementation details of that :
public static int signum(int i) {
// HD, Section 2-7
return (i >> 31) | (-i >>> 31);
}
Integer::signum says : I'll give you -1 if the number is negative, 0 if number is zero and 1 if number is positive. This is fairly trivial via some nested if/else for example.
Instead JDK uses a solution that is a bit more fancy. (x >> 31) | (-x >>> 31). Looks easy right? the first part : x >> 31 is signed shift to the right; it's called signed because it keeps the sign after the shift.
Suppose we live in a world where 4 bits numbers exist only (for simplicity).
We have 0100 (+4), a single shift 0100 >> 1 will make it 0010 (+2). Now, if our number is 1100 (-4; the first bit is the sign), a shift signed to the right : 1100 >> 1 is 1110 (-2). Do a division, but keep the sign.
Thus if we shift 31 times, we throw away the last 31 bits of the number, move the bit for the sign in the least significant position and keep the original sign. Or in simple words take the 31 bit, put it into 0 position and throw away everything else.
0 00000 ..... 11111
x --------------->0 // x is kept
ignore
The second part -x >>> 31 is a unsigned shift, meaning the sign is not kept when we shift.
For example 0100 >>> 1 (+4) will give you 0010 (+2). Nothing is really different so far from the signed shift and the example above. The interesting part comes when numbers are negative:
1100 (-4) and we try to shift it once : 1100 >>> 1, because the sign is not kept, we put zero in the most significant bit and move to the right, thus we get : 0110 (+6!).
In reality, taking 32 bits into the picture. -4 == 1111...111100 and we shift it to the right: sign is zero, everything else is moved to the right, thus: 0111...11110 or Integer.MAX_VALUE - 1.
System.out.println(-4 >>> 1);
System.out.println(Integer.MAX_VALUE - 1);
Thus the part x >>> 31 will move the sign bit into the least significant position, zeroing everything else. No matter the number you give it, you will always get 1 or 0.
1 00000 ..... 11111
x --------------->1 // x is "zeroed also"
ignore
And the addition of -x to that x >>> 31 is simply done so that | would work correctly satisfy our needed result.
This code segment:
(x >>> 3) & ((1 << 5) - 1)
apparently results in a 5-bit integer with bits 3 - 7 of x.
How would you go about understanding this?
Let's look at ((1 << 5) - 1) first.
1 << 5 is equal to 100000 in binary.
When we subtract 1, we're left with 11111, a binary number of five 1s.
Now, it's important to understand that a & 0b11111 is an operation that keeps only the 5 least significant bits of a. Recall that the & of two bits is 1 if and only if both of the bits are 1. Any bits in a above the 5th bit, therefore, will become 0, since bit & 0 == 0. Moreover, all of the bits from bit 1 to bit 5 will retain their original value, since bit & 1 == bit (0 & 1 == 0 and 1 & 1 == 1).
Now, because we shift the bits of x in x >>> 3 down by 3, losing the three least significant bits of x, we are applying the process above to bits 4 to 8 (starting at index 1). Hence, the result of the operation retains only those bits (if we say the first bit is bit 0, then that would indeed be bit 3 to bit 7, as you've stated).
Let's take an example: 1234. In binary, that's 10011010010. So, we start with the shift by 3:
10011010010 >>> 3 = 10011010
Essentially we just trim off the last 3 bits. Now we can perform the & operation:
10011010
& 00011111
--------
00011010
So, our final result is 11010. As you can see, the result is as expected:
bits | 1 0 0 1 1 0 1 0 0 1 0
index | 10 9 8 7 6 5 4 3 2 1 0
^-------^
(x >>> 3)
Shifts x right 3 bits logically, i.e. not sign-extending at the left. The lower-order 3 bits are lost. (This is equivalent to an unsigned division by 8.)
1 << 5
Shifts 1 left 5 bits, i.e. multiplies it by 32, yielding 0b00000000000000000000000000100000.
-1
Subtracts one from that, giving 31, or 0b00000000000000000000000000011111.
&
ANDs these together, yielding only the lower-order 5 bits of the result of x >>> 3, in other words bits 3..7 of the original x.
"How would you go about understanding this?".
I assume that you are actually asking how you should go about understanding it. (As distinct from someone just explaining it to you ...)
The way to understand it is to "hand execute" it.
Get a piece of paper and a pencil.
Based on your understanding of how Java operator precedence works, figure out the order in which the operations will be performed.
Based on your understanding of each operator, write the input patterns of bits on the piece of paper and "hand execute" each operation ... in the correct order.
If you do this a few times with a few values of x, you should get to understand why this expression gives you a 5 bit number.
If you repeat this exercise for a few other examples, you should get to the point where you don't need to go through the tedious process of working it out with a pencil and paper.
I see that #arshajii has essentially done this for you for this example. But I think you will get a deeper understanding if you do / repeat the work for yourself.
One thing to remember about integer and bitwise operations in Java is that the operations are always performed using 32 or 64 bit operations ... even if the operands are 8 or 16 bit. Another thing to remember (though it is not relevant here) is that the right hand operand of a shift operator is chopped to 5 or 6 bits, depending on whether this is a 32 or 64 bit operation.
This question already has answers here:
Difference between >>> and >>
(9 answers)
Closed 9 years ago.
I try the code
System.out.println( 16 >>> 3);
and the output is 2 !
but how does this work? What is the syntax?
16 >> 3 is a bitshift to the right, and is equivalent to dividing by 8 (2 ** 3).
16 -> 00010000
^
\
\
2 -> 00000010
This is called right-shift with zero-fill (also called - unsigned right shift).
To make it easy to understand, for every shift, your number is divided by 2. So:
16 >>> 3 == 16 / 2^3 == 16 / 8 == 2
For more details see, JLS - Shift Operators.
For real visualization, take a look at the bit representation of the two numbers:
16 - 00010000
16 >>> 3 - 00000010 == 2
Another note, the 3 chevrons indicate an unsigned right bit shift. Although it does not make a difference in this example...
The extra > indicates the sign is not reserved, an example:
-128 >> 2 = -128 / 2^2 = -32
The signed bit is retained giving:
(1) 10000000 >> 2 = (1) 100000
11111111 11111111 11111111 10000000 >> 2 = 1111111 11111111 11111111 11100000
If >>> is used then the signed bit is also shifted converting it to a positive number.
-128 >>> 2 = 536870896
11111111 11111111 11111111 10000000 >> 2 = 0011111 11111111 11111111 11100000
The >>> operator is performing an unsigned right-shift of bits, when applied to an integer it has the effect of dividing by two. In particular, if the integer is a power of two, each right-shift exactly halves the value. For example:
16 >>> 1 // returns 8
16 >>> 2 // returns 4
16 >>> 3 // returns 2
In binary form, 16 is represented as 10000. If we shift the value three times to the right it ends up as 00010, which is 2. Also, take a look at the Java tutorial.
16 in binary is 00010000. You are shifting the bits right three positions which results in 00000010 which is 2
This is a bit shift, which is dividing by 2^3 (due to shifting by 3 positions) and truncating(rounding down) as we are not doing fillaround.
When using >>> we move to the right and divide.
When using <<< it goes opposite, so you'd multiply by the correct power of 2.
Bit shifts are a type of bitwise operation that operates on a primitive(almost always number's) bits directly.
It's an unsigned right shift operator, and the above shifts 3 times.
i.e. it divides by 2 each time, giving you 2.
See here for more information on Java operators.
You're using a bitwise shift consult this post
In binary, every 0 is an increasing magnitude of the power 2 for example:
10000 = 16
01000 = 8
00100 = 4
00010 = 2
00001 = 1
The expression 16 >>> 3 in java is saying to move the bit over 3 places, so we are left with 2.
I need a function that extracts last N bits in an integer (N < 32 so the result is always positive). I cannot seem to work it out myself.
My first approach was to left shift (32 - n) bits then shift right (32 - n) bits, however Clojure converts the first result to BigInt thus I'm unable to get rid off the first 32-n bits.
Could anybody help please? Thanks!
I think what you want is something using bitwise and, for instance:
(defn low-bits [x n]
"Get the lowest n bits of x"
(bit-and x (unchecked-dec (bit-shift-left 1 n))))
Taking n 8, (bit-shift-left 1 8) gives us 256, then (dec 256) gives us 255, a number which has the lowest 8 bits set and the higher bits 0. Then the bitwise and will give us a number where the lowest 8 bits are whatever they were in x, and the higher bits are all 0 (which is what you want I think?).
Disclaimer: This is probablty the 4th Clojure function I've written, so I'm just learning too...
1)
I understand that when you're converting binary to decimal the left most bit represents 0, 1...so on. So for example to convert 0001 to decimal it is 0*2^0+0*2^1+0*2^2+1*2^3 so the decimal value would be 8.
2)
When for example you have signed hex 0x80 which will be converted to binary 1000 0000 however in order to compute the decimal value for this binary representation it is signed so we have to invert 7 bits so we get 1111111 and add 1 which gives us 10000000 which is -128.
My question is why in the second case when we're computing the decimal for the signed byte we had to start from right most bits as 0 so we have ....+1*2^8. Why isn't the 2^0 the left most bit as we computed in 1) for the second case?
Thanks.
No, usually binary is stated the other way...0001 is 1, 1000 is 8.
I answer to point 1, not quite. 0001 is actually 1 while 1000 is 8. You appear to be coming from the wrong end. The binary number 1101, for example would be:
+------ 1 * 2^3 = 8
|+----- 1 * 2^2 = 4
||+---- 0 * 2^1 = 0
|||+--- 1 * 2^0 = 1
|||| --
1101 = 13
For point 2, the easiest way to turn a bit pattern into a signed number is to first turn it into an unsigned value (0x80 = 128), then subtract the bias (256 for eight bits, 65536 for 16 bits and so on) to get -128.
The bias should only affect the calculation at the end of the process, it's a way to map the range 0..255 to -128..127, or 0..65535 to -32768..32767.