Unique ID generation Algorithm - java

I have found an code in my project for generation of PKs and I simply cannot understand what this code do.
Can anyone give me some directions or ideas or explanation?
Integer typecode = ((AbstractEntity)object).getTypeCode();//this is unique number for every type
Long counter = Long.valueOf(this.fetchNextCounter(typecode.intValue())); //this returns a counter for each type
Integer clusterid = Integer.valueOf(0);
Integer millicnt = Integer.valueOf(0);
Long creationtime = Long.valueOf((new DateTime()).getMillis());
//here is where the magic starts and I cant simply understand a thing
if(typecode.intValue() >= 0 && typecode.intValue() <= 32767) {
long longValue = counter.longValue() << 15 | (long)typecode.intValue() << 48 & -281474976710656L;
longValue += ((long)clusterid.intValue() & 15L) << 44 & 263882790666240L;
longValue += creationtime.longValue() - 788914800000L << 4 & 17592186044400L;
longValue += (long)(clusterid.intValue() >> 2) & 12L;
longValue += (long)millicnt.intValue() & 3L;
longValue &= -8796093022209L;
return Long.valueOf(longValue);
} else {
throw new RuntimeException("illegal typecode : " + typecode + ", allowed range: 0-" + 32767);
}
I would appreciate everyone who can help? The problem we have is that we have typecodes which are bigger then 32767 and as the algorithm shows this doesn't work but why and how can we change it?

Line by line (with added clarifying parentheses):
long longValue = counter.longValue() << 15 | (((long)typecode.intValue() << 48) & -281474976710656L);
It computes the binary-OR of two values:
counter shifted left by 15 bits
typecode shifted left by 48 bits and applied the mask -281474976710656 (the same as 0xFFFF000000000000). This mask seems redundant.
-
longValue += (((long)clusterid.intValue() & 15L) << 44) & 263882790666240L;
It gets the last 4 bits of of clusterid (& 15, same as & 0xF) , shifts it left by 44 bits, then applies the mask 263882790666240L, that is the same as 0xF00000000000. This last mask apply seems to be redundant. Sums it to the result.
longValue += ((creationtime.longValue() - 788914800000L) << 4) & 17592186044400L;
It subtracts the creationtime by 788914800000L (that is the timestamp for 12/31/1994 # 11:00pm (UTC)), shifts 4 bits left, then applies the mask 17592186044400L, that is the same as 0xFFFFFFFFFF0. Sums it to the result.
longValue += (long)(clusterid.intValue() >> 2) & 12L;
Then it gets the cluster id, discards the last 2 bits (>> 2) and applies the mask 12L, that is the same as getting the 3rd and 4th bits (5th and 6th in the original number). Sums it to the result.
longValue += (long)millicnt.intValue() & 3L;
It gets the last 2 bits of millicnt (& 3L). Sums it to the result.
longValue &= -8796093022209L;
Then it applies the the mask -8796093022209L to the reslt, that is the same as 0xFFFFF7FFFFFFFFFF. It in practice zeroes the 44th bit of the resulting number.

The operators <<, >>, | and & are all bitwise operators. The act on the individual bits of the underlying binary value of those numbers. For more information, give this article a read. And then take a sample value and work through the code.

This bit of code is putting parts of the bit representation of the typecode, counter, longvalue, creationtime, clusterid and millicnt after each other. This creates a new number that is unique because the combination of all the above is unique. However the way the values are packed in does mean that you can't have more then 32767 typecodes. There just isn't enough space.
You can see the process in detail by using Long.toBinaryString() to see the bit representations of the input and the longValue after each step.
Since these are primary keys for a database I reckon you can let the database generate the key for you though.

Related

Getting value from MSB of 16 bit register

I have 16 bits register which contain some values in LSB and MSB:
LSB:
At bit 0...1 the value is 0
At bit 2 the values is 0
MBS:
At MSB I need to write value 20
So the value that should be written in register is 0 + 0 + 20 = 160
When I'm reading register the I'm doing it on this way:
for the 1st value in bit [0...1]:
firstVal = (valFromReg & (((1 << 2)-1) << 1) / 2)
secondVal = (valFromReg & 4) / 4
But how to read/convert the third value to get number 20?
In Java, a short is a (signed) 16-bit value. You want to split that into 3 values:
Value a is a 2-bit value in bits 0-1
Value b is a 1-bit value in bit 2
Value c is a 13-bit value in bits 3-15
Bit-wise, that can be represented like this: cccc cccc cccc cbaa
To extract the 3 values from the 16-bit reg value, you'd do this:
short reg = /*register value*/;
int a = reg & 0x0003;
int b = (reg >> 2) & 0x0001;
int c = (reg >> 3) & 0x1fff;
To go the other way, you'd do this:
short reg = (short)((c << 3) | (b << 2) | a);
This of course assumes that the values are within value range, i.e. a = 0-3, b = 0-1, and c = 0-8191.
Some things in the question are not quite clear for me...
like:
At MSB I need to write value 20
back in my times MSB was only 1 bit and was only possible to write true or false...
anyways...
A 16 bits signal fits pretty good in an integer...
so you could basically get that register and manipulate it as an integer, then representing that as a binary number AS STRING will lets you to get the MSB or even the bit at any wanted position...
Do this:
Example
int register = -128;
String foo = String.format("%16s", Integer.toBinaryString(register)).replace(' ', '0');
System.out.println(register);
System.out.println(foo);
System.out.println(foo.charAt(0)); //char at 0 is the MSB....

Finding out number of bits that have changed (bitwise operator)

I have a bit string that is generated based on user input. I also have another bit string that I use to perform bitwise & with the generated bit string. What I would like to know is how to find out how many bits of the generated bit string has changed from the & operation. So let say if I have 10000101 as generated bit string and 00101111 as a second bit string I use for & operation. The output of the process should be 1 since only the first bit of the generate bit string has changed. How do I do that?
What you are looking for is bitwise XOR (exclusively OR), or a^b:
10000101 ^ 00101111 → 10101010
Is is logically equivalent to (~a&b) | (a&~b)
You need to XOR the result with the original to identify which bits were changed:
changedBits = (userInput & generatedInput) ^ userInput
Then, you need to calculate the Hamming Weight of the changedBits value:
int hammingWeight(int i) {
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
return (((i + (i >>> 4)) & 0x0F0F0F0F) * 0x01010101) >>> 24;
}
int numberOfChangedBits = hammingWeight(changedBits);
Adjust as needed depending on how many bits your inputs are.

Odd result when bit shifting in Java

I'm trying to isolate two bytes that are next to each other add them, but there seems to be an extra bit that sometimes shows up and I can't figure out how to get rid of it. It's throwing off the answer.
The code is:
(acc & 0x00000000ff000000L) + ((acc << 8) & 0x00000000ff000000L);
and I'm getting results such as
0x0000000147000000
when it should be
0x0000000047000000
How can I get rid of the 1?
Edit: acc is a long. I'm try to add the 5th and 6th byte and then that value will go into a new long in the 5th byte position.
You need to mask the bits you want at the end, because the addition may carry a bit:
((acc & 0x00000000ff000000L) + ((acc << 8) & 0x00000000ff000000L)) & 0x00000000ff000000L;
I think this might be clearer if you broke it down a little:
acc&=0x00000000FFFF000000L; // isolate bytes 5 and 4
acc+=(acc<<8); // add the two bytes (we'll strip bytes 6 & 4 next)
acc&=0x00000000FF00000000L; // reduce to byte 5 only
which happens to be one less bitwise opperation too.
If I understand correctly, you want to get the value of the 5th and 6th byte, add them together, and store them in a new long that contains just that sum in the 5th byte. This would be done like this:
long 5thByte = acc & 0xff00000000 >>> 32;
long 6thByte = acc & 0xff0000000000 >>> 40;
long sum = 5thByte + 6thByte;
long longWithNewByte = sum << 32;
This will of course carryover to the 6th byte if the sum is higher than 255. To get rid of that carryover, you can use another mask.
long longWithNewByte &= 0xff00000000;

Obtain a specific subset of bits of an int in Java

How would I obtain a specific subset, say bits 5-10, of an int in Java?
Looking for a method where one can pass in specific bit positions. I'm not sure how I would create a mask that changes given the input, or even if that is how one should go about doing it.
I know this is how one would get the front say 10 bits of an int: (I think)
int x = num >> 22;
Say you have a number n, and want bits from i to j (i=5, j=10).
Note, that i=0 will give you the last bit
int value = n & (((1 << (j-i)) - 1) << i );
will give you the result.
The left part is obvious: you have a value, and you will put a bitmask on it.
The value of the mask is ((1 << (j-i)) - 1) << i. It says:
Take a 1 bit (value: 0000000000000001)
Shift it left j-i times (value: 2^(10-5) = 2^5 = 32 = 0000000000100000)
Deduct 1 (value: 31 = 0000000000011111) - have you seen the lowest bits reversed?
Shift it left i times (value: 31*32=992 = 0000001111100000)
So, you have got the bitmask for bits 5 - 10 (more precisely, from 5 to 9, since 10th is not included).
To obtain value of bit 1 (bits are indexed from 0 to 31)
int val = bits & 0x002;
To obtain value of bit 16
int val = bits & (1<<16);
To obtain value of bit n
int val = bits & (1<<n);

How to get the value of a bit at a certain position from a byte?

If I have a byte, how would the method look to retrieve a bit at a certain position?
Here is what I have know, and I don't think it works.
public byte getBit(int position) {
return (byte) (ID >> (position - 1));
}
where ID is the name of the byte I am retrieving information from.
public byte getBit(int position)
{
return (ID >> position) & 1;
}
Right shifting ID by position will make bit #position be in the furthest spot to the right in the number. Combining that with the bitwise AND & with 1 will tell you if the bit is set.
position = 2
ID = 5 = 0000 0101 (in binary)
ID >> position = 0000 0001
0000 0001 & 0000 0001( 1 in binary ) = 1, because the furthest right bit is set.
You want to make a bit mask and do bitwise and. That will end up looking very close to what you have -- use shift to set the appropriate bit, use & to do a bitwise op.
So
return ((byte)ID) & (0x01 << pos) ;
where pos has to range between 0 and 7. If you have the least significant bit as "bit 1" then you need your -1 but I'd recommend against it -- that kind of change of position is always a source of errors for me.
to get the nth bit in integer
return ((num >> (n-1)) & 1);
In Java the following works fine:
if (value << ~x < 0) {
// xth bit set
} else {
// xth bit not set
}
value and x can be int or long (and don't need to be the same).
Word of caution for non-Java programmers: the preceding expression works in Java because in that language the bit shift operators apply only to the 5 (or 6, in case of long) lowest bits of the right hand side operand. This implicitly translates the expression to value << (~x & 31) (or value << (~x & 63) if value is long).
Javascript: it also works in javascript (like java, only the lowest 5 bits of shift count are applied). In javascript any number is 32-bit.
Particularly in C, negative shift count invokes undefined behavior, so this test won't necessarily work (though it may, depending on your particular combination of compiler/processor).

Categories

Resources