I need to find out if int n is a power of two and my approach is to convert n to a hex number and check each bit (0 or 1). However, I've never used hex numbers in Java, could anyone help me out here?
Both converting to a String and replacing using a regular expression is expensive.
A simple way to check for a (positive) power of two is to check the number bits set.
if (x > 0 && Long.bitCount(x) == 1)
While Long.bitCount looks complicated, the JVM can replace it with a single machine code instruction.
The canonical way (which you will encounter a lot when googling how to test for powers of two, and you will probably encounter it in code) to test for powers of two is
x != 0 && (x & x - 1) == 0
It is often encountered with more parenthesis (precedence paranoia?)
x != 0 && (x & (x - 1)) == 0
It is common to skip the x != 0 check and guarantee zero can't be an input, or (often enough) zero is "as good as" a power of two in some sense.
You can of course change the condition to x > 0 if you don't want to consider -2147483648 a power of two, though in many cases it would be (because it's congruent to 231 modulo 232, so interpreted unsigned it's a PoT, and anyway it only has one bit set so it was a PoT all along)
So what's the deal with x & x - 1. It unsets the lowest set bit, but let's look at it in the context of PoTs.
Let's ignore x<2 and say x has the form a10k (ie an arbitrary string of bits followed by a one followed by k zeroes), subtracting 1 from it gives a01k because the -1 borrows through all the trailing zeroes until it reaches the lowest set bit, unsets that bit, then the borrow dies and the top bits are unchanged.
If you take the bitwise AND of a10k and a01k you get a00k because something ANDed with itself is itself again (the a), and in the tail there's always a 0 involved in the AND so it's all zeroes.
Now there are two cases. 0) a=0. Then the result is zero, and we know we started out with x of the form 10k which is a power of two. And 1) a!=0, then the result isn't zero either because a still appears in it, and x wasn't a power of two because it has at least two set bits (the lowest set bit which we explicitly looked at, and at least one other somewhere in a).
Well actually there are two more cases, x=0 and x=1 which were ignored. If we allow k to be zero then x=1 is also included. x=0 is annoying though, in x & x - 1 there is that x as the left operand of &, so the result must be zero no matter what happens in the right operand. So it falls out as a special case.
There is no reason to convert to hex to check bits. In fact, that actually makes it harder. The following line produces a binary String for an int variable "num":
String binary = Integer.toString(num, 2)
That String will only have 1s and 0s in it. Then eliminate any 0s:
String ones = binary.replace("0", "");
If the length of the String is more than one, there there is more than one bit, which means it is not a power of 2. If the length is 0, it means the number had no bits, which means it is 0.
Related
I was wondering about the differences between positive and negative zero in different numeric types.
I understand the IEEE-754 for floating point arithmetic and bit representation in double precision so the following didn't come as a surprise
double posz = 0.0;
double negz = -0.0;
System.out.println(Long.toBinaryString(Double.doubleToLongBits(posz)));
System.out.println(Long.toBinaryString(Double.doubleToLongBits(negz)));
// output
>>> 0
>>> 1000000000000000000000000000000000000000000000000000000000000000
What did surprise me and showed me that im clueless about the bit representation of long type in java is that even if i shift right (unsigned >>>) then the binary representation of both positive and negative zero is the same
long posz = 0L;
long negz = -0L;
for (int i = 63; i >= 0; i--) {
System.out.print((posz >>> i) & 1);
}
System.out.println();
for (int i = 63; i >= 0; i--) {
System.out.print((negz >>> i) & 1);
}
// output
>>> 0000000000000000000000000000000000000000000000000000000000000000
>>> 0000000000000000000000000000000000000000000000000000000000000000
so i am wondering what does java do from a bit representation when i write the following
long posz = 0L;
long negz = -0L;
Does the compiler understand that they are both zero and disregards the sign (and so assignes 0 to the sign bit) or is there other magic here?
or is there other magic here?
Yes. 2's complement.
2's complement is a bit magical. It accomplishes 2 major objectives. Before getting into that, let's first stew on the notion of negative zero for a moment.
Negative zero is kinda weird. Why does it exist at all?
Negative zero isn't actually a thing. Ask any mathematician "Hey, so, what's up with negative zero?" and they'll just look at you in befuddlement. It's not a thing. Mathematically, 0 and -0 are utterly identical. Not just 'nearly identical', but 100%, fully, in all possible ways, identical. We don't generally want our numbers to be capable of representing both 5.0 as well as 5.00 - as those two are entirely, 100%, identical. If you don't think that a value system ought to waste bits trying to differentiate between 5.0 and 5.00, then it's equally bizarro to want the ability to represent -0.0 and +0.0 as distinct entities.
So, wanting -0 in the first place is kinda weird. All the numeric primitives (long, int, short, byte, and I guess char which is technically numeric too) all cannot represent this number. Instead, long z = -0 boils down to:
Take the constant "0".
Apply the 'negate' operation to this number (- is a unary operator. Just like 2+5 makes the system calculate the binary operation of "addition" on elements 2 and 5, -x makes the system calculate the unary operation of "negation" on element x. Applying the negation operation to 0 produces 0. It's no different from writing, say, int x = 5 + 0;. That +0 part doesn't do anything. The - in front of -0 doesn't do anything. In contrast to -0.0 where it does do something (gets you negative zero, the double value, instead of positive zero).
Store this result in z (so, just 0 then).
There is no way to tell if that minus is there. They both result in ALL ZERO bits, and hence, there is no way for the computer to tell if you initialized that variable with the expression -0 or with +0. Again in contrast to double where as you noticed there's a bit different.
So why does double have it then?
Let's stew a bit on the notion of doubles and IEEE-754 math.
A double takes 64 bits. From basic pure mathematical principles then, a double is as incapable of representing more than 2^64 different possible values you are capable of breaking the speed of light or making 1+1=3.
And yet, a double aims to represent all numbers. There are way more numbers between 0 and 1 than 2^64 options (in fact, an infinite amount of numbers exist between 0 and 1), and that's just 0 to 1.
So, how doubles actually work is different. A few less than 2^64 numbers are chosen from the entire number line. Let's call these the blessed numbers.
The blessed numbers are not equally distributed. The closer you are to 1, the more blessed numbers exist. In other words, the distance between 2 blessed numbers increases as you move away from 1. For example, if you go from, say, 1e100 (a 1 with a hundred zeroes) and want to find the next blessed number, it's quite a ways. It's in fact higher than 1.0! - 1e100+1 is in fact 1e100 again, because the way double math works is that after every single last mathematical operation you to do them, the end result is rounded to the nearest blessed number.
Let's try it!
double d = 1e100;
System.out.println(d);
System.out.println(d + 1);
// prints: 1.0E100
// 1.0E100
But that means.. double values don't actually represent a single number!!. What any given double represents is in fact this concept:
An unknown number whose value lies between [D - 𝛿, D + 𝛿], where D is the blessed number that is closed to this unknown number this value represents, and, and 𝛿 is half of the distance between D and the next nearest blessed number on either side.
Given that usually 𝛿 is incredibly small, this is 'good enough'. But this weirdness does explain why you really, really do not want any business at all with double if accuracy is important (such as with currencies. Don't store those in doubles, ever!)
Given that, what does -0.0 represent? not actually just 0. It represents, specifically: An unknown number whose value lies between [-𝛿, 0] where 0 is real zero (and this, has no sign), and 𝛿 is Double.MIN_VALUE: the smallest non-zero positive number representable with a double.
That's why -0.0 and +0.0 both exist: They are in fact different concepts. Rarely relevant, but sometimes it is. In contrast to e.g. long where 5 just means 5 and not "between 4.5 and 5.5", because longs fundamentally don't recognize that fractional parts exist in the first place. Given that 5 just means 5, then 0 just means 0, and there is no such thing as negative zero in the first place.
Now we get to 2's complement
2's complement is a cool system. It has two neat properties:
It only has the one zero.
It does not matter if you treat the bit sequence as signed-by-way-of-2s-complement or as unsigned, for the purposes of the operations: Addition, Substraction, Increment, Decrement, zero-check. The modifications you do to the bits to implement those operations is identical.
It DOES matter for greater than, less than, and divide.
2's complement works like this: To negate a number, take all bits and flip them (i.e. do a NOT operation on the bits). Then, add 1.
Let's try it!
int x = 5;
int y = -x;
for (int i = 31; i >= 0; i--) {
System.out.print((x >>> i) & 1);
}
System.out.println();
for (int i = 31; i >= 0; i--) {
System.out.print((y >>> i) & 1);
}
System.out.println();
// prints 00000000000000000000000000000101
// 11111111111111111111111111111011
As we can see, the 'flip all bits and add 1' algorithm was applied.
2s complement is, of course, reversible: If you do 'flip all bits and add 1' twice in a row you get the same number out.
Now let's try -0. 0 is 32 0 bits, then flip them all, then add 1:
00000000000000000000000000000000
11111111111111111111111111111111 // flip all
100000000000000000000000000000000 // add 1
00000000000000000000000000000000 // that 1 fell off
and because ints can only store 32 bits, that final '1' falls off of the end. And we're left with zero again.
Now let's go with bytes ( abit smaller) and try to add, say, 200 and 50 together.
11001000 // 200 in binary
00110010 // 50 in binary
-------- +
11111010 // 250 in binary.
now let's instead go: Oh wait, whoops, that was an error, actually these numbers are in 2s complement. That wasn't 200, nono. 11001000 is a bit sequence that actually means (let's apply the 'flip all bits, add 1' scheme: 00111000 - it's actually -56. So the operation was meant to represent '-56 + 50'. Which is -6. -6 in binary is (write out 6, flip bits, add 1):
00000110
11111001
11111010
hey now, look at that, nothing changed! It's the same result! So, when the computer does x + y, where x and y are numbers, the computer does not care. Whether x is "an unsigned number" or "a signed with 2s complement number", the operation is identical.
That's why 2s complement is applied. It makes math MUCH faster. The CPU doesn't have to futz about with branching out to deal with sign bits.
In this sense it is more correct to say that in java, int, long, char, byte and short are neither signed nor unsigned, they just are. At least for the purposes of +, -, ++, and --. No the idea that int is signed is fundamentally a property of e.g. System.out.println(int) - that method chooses to render the bitsequence 11111111111111111111111111111111 as "-1" instead of as 4294967296.
long has no such thing as negative zero. Only float and double have a different representation of positive and negative zero.
This is a well-known function to compute the next nearest power of two for positive arguments. However I don't have much experience in bit twiddling to grok the logic/theory behind it. Would you kindly explain why and how that works? Particularly, the choice of 1,2,4,8,16 for shifting and if the range of the argument was greater what would be used, for example, for a long? Why logical shift instead of arithmetic and finally, what does ORing shifted arg accomplish?
static int lowestPowerOfTwoGreaterThan(int arg) {
arg |= (arg >>> 1);
arg |= (arg >>> 2);
arg |= (arg >>> 4);
arg |= (arg >>> 8);
arg |= (arg >>> 16);
return ++arg;
}
It's really simple if you track the changes to the value. A power of two has only one set bit e.g 100, 10000000, 10000000000, which means that a power of two, minus one, is a sequence of ones, e.g. 10000 - 1 = 1111. So what the function does is change any number to a sequence of ones (without moving its highest 1 bit) and then add one, e.g. it changes 10000001000111001 (66105) to 11111111111111111 (131071) and adds one to make 100000000000000000 (131072).
First, it ORs the value by itself shifted 1 bit to the right. This has the effect of lengthening all runs of 1 in the value.
10000001000111001
OR 01000000100011100
=================
11000001100111101
You now notice that each run of zeroes is preceded by at least two ones, so instead of shifting by one again, we can speed up the process by shifting by two bits instead of one.
11000001100111101
OR 00110000011001111
=================
11110001111111111
Now, each run of zeroes is preceded by at least four ones, so we shift by four this time, and OR the values again.
11110001111111111
OR 00001111000111111
=================
11111111111111111
Repeating this logic, the next shift distance will be 8, then 16 (stop here for 32-bit values), then 32 (stop here for 64-bit values). For this example, the result remains unchanged for further shifts since it is already a sequence of ones.
This method changes any binary number to a sequence of ones. Adding 1 to this, as stated before, produces the next greatest power of two.
To reverse an integer and put it into a list, one would do the following (where x is some integer):
int lastDigit = x;
while(lastDigit != 0)
{
list.add(lastDigit % 10);
lastDigit /= 10;
}
So if x was 502, 2 0 and 5 would get added to the list.
This is obviously really useful, but until yesterday I thought the only way to do something like this was by converting the int to a string first.
I'm not sure if this is just common knowledge but I had not seen this method before today. I would like to understand how it works instead of merely memorizing it.
Could someone explain why the number modulus 10 gives the last digit, and why dividing it by 10 gives the next digit on the next iteration? Why would it eventually equal 0?
The modulus operator gives you the remainder from doing a division calculation.
502 % 10 is 2 because 502/10 = 50 plus a remainder of 2.
Therefore the remainder in this calculation is 2, meaning 2 will be added to the list.
The division by ten in the next line is performed using integer arithmetic, so 502/10 gives a result of 50.
Any non-negative number less than 10 will give a result of zero, ending the loop.
Think of % 10 as getting the least significant (right most) digit in decimal system (hence 10).
And then think of / 10 as shifting all digits one place right (also decimal). You obviously have to do it until the number is 0. All remaining digits can be understood as leading zeros in this case.
In binary system you can also use the bitwise operations & 1 and >> 1 instead of modulo (% 2) and integer (/ 2) divisions.
The list append operation (here add) is the one that reverses the order. The operations above are just for extraction of the single digits.
I have the following code that returns the number of nodes in a tree when a complete Binary Tree is layer layers tall:
public static long nNodesUpToLayer(int layer) {
if (layer < 0) throw new IllegalArgumentException(
"The layer number must be positive: " + layer );
//At layer 0, there must be 1 node; the root.
if (layer == 0) return 1;
//Else, there will be 1 + 2 * (the number of nodes in the previous layer) nodes.
return 1 + (2 * nNodesUpToLayer(layer - 1));
The odd thing is, when I input 63 into the function (the minimum value that produces this), it gives me back -1. At 62, it gives back 9223372036854775807, so this seems to be caused by an overflow.
Shouldn't it give me back the minimum value of Java's long + the amount that it was overflowed by? Regardless of the input that I give it though (passed 62), it will always return -1 instead of a seemingly random number that I'd expect from an overflow.
I'm not entirely sure how to debug this, since it's recursive, and the value I'm interested in will only be evaluated once the the function has reached the base-case.
You are correct, it is an overflow error of a 64 bit signed integer. The reason it goes to -1 instead of the minimum integer value is because you are doubling it, not simply adding one.
9223372036854775807 in Two's Complement is 63 1s:
0111 1111 ... 1111 1111
To double it in binary, simply perform a left shift:
1111 1111 ... 1111 1110
However, this number in Two's Complement is not twice 9223372036854775807, but rather -2. Then, of course, you add 1 to that before returning to get your -1 result.
Actually, it is returning you the correct amount. It's just that "the amount that it was overflowed by" is exactly right to make the answer -1 :)
Consider this:
The number of nodes in a complete binary tree is 2^n - 1 for n layers. Hence its binary representation is 0000...00111...111 where the number of 1s is precisely the number of layers minus 1. As soon as you reach the length of the long you're stuck at the truncated 11...11, which is precisely -1
I always prefer the visualizations with things like this.
(min long)
v
<--------------------||--------------------------------------->
^ ^
(max long, n) -1
Where n is 9223372036854775807 - the value you have right before you multiply by 2. Instead of multiplication, though, think of it as addition. n + n. By seeing it on a number line, you can see that you'd end up at -2. You're basically overflowing past most of the negative numbers.
So that my answer contributes something meaningful compared to the others, one helpful tool in situations like this is to break your arithmetic into multiple lines in order to debug. You could write:
int a = nNodesUpToLayer(layer - 1);
int b = 2 * a;
int c = 1 + b;
return c;
You're essentially enforcing order-of-operations as you'd expect it(which may help you realize the program is doing things out of the order you want them in), but it also lets you go into the debugger and see the intermediate values of your calculations. Here you would have noticed b == -2. Why is b == -2? Well, it must be because 2 * a == -2, etc.
This is likely an easy solution that is simply eluding me. Specifically, I am creating locations on a canvas dynamically using a sin() function for equidistant points on a circle. Once these points are created, I am animating a shape moving from one point to the next by calculating the slope between points and redrawing the shape at each slope step.
Problem is, depending on the coordinate values, the slope step may just be one step from point a to point b. I need the shape to move along the path, not just jump point to point.
What I want to do is force the location coordinates (x, y) to be even numbers allowing for slope values to always be reducible. So, the simple part of question is...
How do I check if an int value is even? If it is not, I will simply add 1 to the coordinate value.
int newNumber = someInt % 2 == 0 ? someInt : someInt + 1;
To see if an integer is even:
Check if its value is congruent to 0 modulo 2. That is value MOD 2 == 0. In C-style languages this is usually expressed as value % 2 == 0.
Alternatively, check the value of bit 0. That is value BITWISE-AND 0x01 == 0. In C-style languages this is usually expressed as (value & 0x01) == 0.
If you do not care which direction you round, you can even-ize an integer in a single operation by taking its value bitwise-and a mask of 0xFFFE (of course padded to the width of your integer), which will force set the 0 bit to zero. That is value := value BITWISE-AND 0xFFFE, or in C-style languages value &= 0xFFFE.
Do a mod 2 on it. If the remainder is 0, it's an even number.
VB:
Dim even = (3 mod 2 = 0 )
It's hard to give you specifics since you haven't given many, but you should look into the
Modulo operation.
For integers, while using modulo will give you the correct answer, it requires division. Division isn't as fast as bitwise operations. For what you need, a bitwise AND is sufficient.
if(x & 0x1)
{
sdt::cout << "x is odd" << std::endl;
}
else
{
std::cout << "x is even" << std::endl;
}
The key is that all positive powers of two are even. Therefore the only way a binary representation of an integer can be odd is if the first bit is set.