Pack a date into an int variable (Java) [closed] - java

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have a problem that asks from me to pack and unpack a calendaristic date in an int variable. For example, 20th February 2007 will be represented as folows:
first 5 bits will be reserved for the day
the next 4 bits
will be reserved for the month
the last bits will be reserved for the year
Unfortunately, this is all the information I have. Any suggestions?

Assuming you are using a 32 bit signed integer and you ignore the sign bit and that by "calendaristic" you mean that it is of the type Calendar then the following method should do the trick:
public static int calToInt(Calendar cal) {
int date = cal.get(Calendar.DAY_OF_MONTH) << 26;
date |= cal.get(Calendar.MONTH) << 22;
date |= cal.get(Calendar.YEAR);
return date;
}
Note that in the implementation of Calendar, January is 0, if you want January to be represented by 1, then ensure that you add 1 to the month. Also note that based on my assumptions, your year has 22 bits to work with so will work until the year that is 2^22 i.e the year 4194304, which should be more than sufficient.
Explanation
You may not be interested in the rest but I like to explain how things work even if I only provide a rough overview:
The way this works is by taking the calendar object, getting the day and shifting it 26 bits to the left (that's what the << 26 does) which would mean that with day of month being a maximum of 5 bits, the day will actually start on the second bit of a 32bit int. This is to avoid the first bit which represents if the int is negative. If you wish to fill the full int then change 22 to 23 and 26 to 27 which will give you a bit extra for your year (double in fact). Likewise with the month of the year, it is shifted 22 bits to the left so that it comes after the day of month with a maximum consumption of 4 bits.
The |= operator is a bitwise or assignment operator. What this does is do a bitwise or of the thing on the left, with the thing on the right and assign to the thing on the left. You can do this in one line, but this is much clearer in my opinion and in terms of byte code will result in the same thing. What is meant by OR is that if either bit from either the left or right is a 1 then the output will contain a 1 in that position. This is how the individual parts are put together.
If the year did happen to be larger than the stated max, it would mess things up.
To Reverse:
In order to get this int back into a Calendar object the following method can be used:
private static Calendar intToCal(int date) {
int day = date >> 26;
int month = (date & 0b00000011110000000000000000000000) >> 22;
int year = date & 0b00000000001111111111111111111111;
return new GregorianCalendar(year, month, day);
}
This works using bitmasks and bit shifting. So the first one just shifts 26 bits along (all other bits to the right get lost and we are left with the day.
With the month and day bitmasks are used. I have written these in binary format to make it clearer exactly what it does. I am using a logical and to get only the bits from the int that I want. in the month, only the bits marked with a 1 in the bitmask will be left (this removes the day of month before we shift). I have also gotten rid of the bits on the right of the month but this is not required and will be cut off like they were in the first when the right bit shift is performed. The year just needs the mask as those last 22 bits are just simply the year in binary form. Again, I have ignored the sign bit however this is not explicit in the first and if a negative was passed it would mess this up. To fix this a mask must be applied to the day to mask the sign bit.

Change the sequence as per your requirement.
Its simple use of String#substring() and Integer#toBinaryString().
int date = 20;
int month = 2;
int year = 2007;
String d = String.format("%0$5s", Integer.toBinaryString(date));
String m = String.format("%0$4s", Integer.toBinaryString(month));
String y = String.format("%0$23s", Integer.toBinaryString(year));
String str = y + m + d;
str = str.replace(' ', '0');
System.out.println(str);
int number = 0;
for (int i = 0; i < str.length(); i++) {
number = (number << 1) | ((str.charAt(i) != '0') ? 1 : 0);
}
System.out.println(number);
System.out.println(Integer.toBinaryString(number));
get the date back from returned number
String str1=String.format("%0$32s", Integer.toBinaryString(number)).replace(' ', '0');
int originalYear= Integer.parseInt(str1.substring(0,23), 2);
int originalMonth= Integer.parseInt(str1.substring(23,27), 2);
int originalDate= Integer.parseInt(str1.substring(27,32), 2);

Related

Check Leap Year - without using division operation

How to check if the given year is a leap year, without using division operation or
some library method in Java. Is it possible to check this using a bitwise operator?
PS: validation not necessary for centuries
Here are some ways of identifying leap years without using a modulo function.
Firstly, let’s assume (or test) that the year is in the range 1901 - 2099.
A leap year expressed as a binary number will have 00 as the
last two digits. So:
it’s a leap year if year & (not 4) == 0
If you have a function available to truncate a real number to an
integer then this works:
x = trunc(year / 4)
it’s a leap year if x * 4 == year
If you have shift (not circular shift) operators, which I’m sure
Verilog has then:
x = year >> 2
it’s a leap year if (x << 2) == year
If the assumption about the range being 1901 - 2099 is false then you’ll need some extra logic to eliminate 1900, 1800, 1700 and 2100, 2200, 2300 and so on.
Well, sure. Since division or mod by powers of 2 (in this case, 4), is just a bit check.
boolean isLeapYear( int year ) {
return (( year & 3 ) == 0 ); // if the bottom two bits are 0, then the int is divisible by 4
}
Note this isn't perfect, as some centuries aren't leap years, but it seems that's not relevant to your question (as you now state).
If a year is a century year, meaning divisible by 100, then it needs to be divisible by 400 to be called as a leap year.
If a year is not a century year, then it needs to be divisible by 4 to be called as a leap year.
Below Code uses binary search to check if a number is divisible by another number or not(since / is not allowed, I am not sure if you could use % though).
public static boolean isLeapYear(int year){
return isDivisible(1,year,100,year) ? isDivisible(1,year,400,year) : isDivisible(1,year,4,year);
}
private static boolean isDivisible(int low,int high,int divisor,int dividend){
int mid = 0;
while(low <= high){
mid = low + ((high - low) >> 1);
int result = divisor * mid;
if(result == dividend) return true;
else if(result > dividend) high = mid - 1;
else low = mid + 1;
}
return false;
}
Yes, you can do it without using any arithmetic operations. Use a Map which maps from year to a boolean - whether the year is a leap year or no.
Year.isLeap(someYear)
You should be more specific with your requirements, this is a site for programmers :)

How can I mask a hexadecimal int using Java?

I have an integer that contains a hexa value. I want to extract the first characters from this hexa value like it was a String value but I don't want to convert it to a String.
int a = 0x63C5;
int afterMask= a & 0xFFF;
System.out.println(afterMask); // this gives me "3C5" but I want to get the value "63C"
In my case I can't use String utilities like substring.
It's important to understand that an integer is just a number. There's no difference between:
int x = 0x10;
int x = 16;
Both end up with integers with the same value. The first is written in the source code as hex but it's still representing the same value.
Now, when it comes to masking, it's simplest to think of it in terms of binary, given that the operation will be performed bit-wise. So it sounds like you want bits 4-15 of the original value, but then shifted to be bits 0-11 of the result.
That's most simply expressed as a mask and then a shift:
int afterMask = (a & 0xFFF0) >> 4;
Or a shift then a mask:
int afterMask = (a >> 4) & 0xFFF;
Both will give you a value of (decimal) 1596 = (hex) 63C.
In this particular case, as your input didn't have anything in bits 12+, the mask is unnecessary - but it would be if you wanted an input of (say) 0x1263c5 to still give you an output corresponding to 0x63c.
If you want "63C" all you need is to shift right 4 bits (to drop the right most nibble). Like,
int a = 0x63C5;
int afterMask = a >> 4;
System.out.println(Integer.toHexString(afterMask));
Outputs (as requested)
63c
int a = 0x63C5;
int aftermask = a >> 4 ;
System.out.println( String.format("%X", aftermask) );
The mask you need to use is 0XFFF0

Generate a random number and add 0 before it to ensure fixed number of digits

so I am trying to generate a random number. I am going to append the day and month as integers before the random number. This I am able to do by using the following code.
Calendar calendar;
calendar=Calendar.getInstance();
int day= calendar.get(Calendar.DAY_OF_MONTH);
int month=calendar.get(Calendar.MONTH)+1; //it treats Jan as 0 hence i add 1
int num= Integer.valueOf(String.valueOf(month)+String.valueOf(day));
Now i need to generate a random number but add 0s before it. For example today is 21st September so numbers will look like
921 (num) + 22334 (random num) = 92122334
921 (num) + 2 (random num) = 92100002
Basically add 0s to the start ensuring number of digits remain the same. The use case of this is an easier way of generating unique order numbers that have an inbuilt time stamp as well. I dont expect to process more than 200 orders a day hence taking a 5 digit random number seems reasonable enough for probability of duplicates to be very small.
Two possible solutions.
Calendar calendar = GregorianCalendar.getInstance();
int num = 0;
num += (calendar.get(Calendar.MONTH) + 1) * 10_000_000;
num += calendar.get(Calendar.DAY_OF_MONTH) * 100_000;
num += your_random_number_lower_100000
second
Calendar calendar = GregorianCalendar.getInstance();
String randomDigits = String.format("%d%02d%05d",
calendar.get(Calendar.MONTH) + 1,
calendar.get(Calendar.DAY_OF_MONTH),
your_random_number_lower_100000
);
You can use String format:
String finalString = String.format("%d%05d", num, randomNum);
Here you can pass first parameter, Your calculation of day and month and second parameter Random number that got.
%05d means: If your integer number digit size will be less than 5 then it will append the 0 (zero) to make the number in 5 digit.
What about
int newnumber = 921*100000 + 2;
that gives 92100002. instead of 2 you can use any random number of course.
If you want to add zeros in front of the 921 so it becomes 0921 and for 1st September 0901 for example, you need to convert it to a string and check the length, and add zeros till you have the length that you want.
You could construct a String by such way:
String value = String.valueOf(randomNum); //your random num should have 5 digits or less
int N = 5; //your length
while (value.length < N)
value = "0" + value;
If you are going to store this as a string (which it seems you are already doing since you are adding 921 and 22334 and getting 92122334?) the easiest way would be to add 0's to the start of the string until it reaches a certain length.
StringBuilder numberString = new StringBuilder(maxSize);
numberString.append(yourNumber);
while(numberString.length() < maxSize)
numberString.insert('0');

Use java to perform binary shifts [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I have to take a binary data in java and perform shifts on it.
For e.g. 11110000 when I right shift it by 2 , i.e. 11110000>>00111100
The problem is that, I don't know how to store such a data in Java, as the byte type converts it to decimal format. I need to use the bit at position 6 and XOR it with some other value.
I just need to know how I can achieve the ability to store binary data and perform the required shifts.
If you're using an integer it'll display it in a number format, you can work around it using Integer.toBinaryString(yourByte)
Second, if you're using an integer to store a binary number in the format of 1... (the leftmost bit is 1) then using the operation >> will shift the number right but enter a "new" 1 into the leftmost bit. What you want to do in such case is actually use >>> which prevents that.
If you're using an int to store your byte, and you want to start doing all kind of bit manipulations than you'll have to use a mask, for example, switching between the 3rd and the 5th bits:
int number = 7; //just an example, here binary rep: 00111 => requested output will be 10011
System.out.println("number = " + Integer.toBinaryString(number));
int mask3Bit = 4;//binary rep: 0100
System.out.println("mask3Bit = " + Integer.toBinaryString(mask3Bit));
int mask5Bit = 16; //binary rep: 10000
System.out.println("mask5Bit = " + Integer.toBinaryString(mask5Bit));
// now we'll create a mask that has all the bits on except the 3rd and 5th bit:
int oppositeMask = -1;
oppositeMask ^= mask3Bit;
oppositeMask ^= mask5Bit;
System.out.println("oppositeMask = " + Integer.toBinaryString(oppositeMask));
//check if the 3rd bit is on:
mask3Bit = number & mask3Bit;
//shift twice to the right
mask3Bit <<= 2;
System.out.println("mask3Bit = " + Integer.toBinaryString(mask3Bit));
//now do the same with the 5th bit
//check if the 5th bit is on:
mask5Bit = number & mask5Bit;
//shift twice to the right
mask5Bit >>= 2;
System.out.println("mask5Bit = " + Integer.toBinaryString(mask5Bit));
//now we'll turn off the 3rd and 5th bits in the original number
number &= oppositeMask;
System.out.println("number = " + Integer.toBinaryString(number));
//and use the masks to switch the bits
number |= mask3Bit;
number |= mask5Bit;
//let's check it out now:
System.out.println("new number = " + Integer.toBinaryString(number));
OUTPUT:
number = 111
mask3Bit = 100
mask5Bit = 10000
oppositeMask = 11111111111111111111111111101011
mask3Bit = 10000
mask5Bit = 0 //here it's zero cause the original number has zero in the 5th bit and we used &. If the bit was on we would have gotten '100'
number = 11
new number = 10011

Java 16 bit alignment

I'm currently dealing with some integer values that represent offsets within a file, the numbers I have need to be aligned on 16-bit boundaries, however I'm a little unsure how to do this.
For example:
First number: 89023
16-bit aligned: 89024
Second number: 180725
16-bit aligned: 180736
Third number: 263824
Already 16-bit aligned, don't need to change it.
This is probably my maths failing me more than anything, but if anyone could advise on how to achieve this in Java, I'd appreciate it.
Thanks!
Update
I think I've just solved it, it's just a matter of modding the value with 16, then working out what's missing from 16.
So for example:
180725 % 16 = 5
16 - 5 = 11
180725 aligned to 16-bits is: 180736
Can someone just confirm that I'm doing that correctly?
Yes that will work. The 16 bit boundary alignment just assures it will be on a multiple of 16. What you are doing there is ensuring that the value hits at the next value of 16, rounded up.
// find how far off of alignment you are, 0-15
offset = num % 16
// determine how much further you need to move the value to achieve 16 bit alignment
// only use if offset > 0, otherwise you are already good
val = 16 - offset
Two possibilities have been described in the other answer/comment. Here are the full implementations:
public static int getAlignment_modulus() {
int offset = num % 16;
int result = offset == 0 ? num : num + 16 - offset;
return result;
}
public static int getAlignment_bitOps() {
return (num + 15) & ~15;
}

Categories