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 :)
Related
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 3 years ago.
Improve this question
This is my attempt to find a well performing algorithm for problem 5 Project Euler - find the smalles possible number that is evenly divisible x and all the numbers below x.
I've tried using one loop make #s and another to test if that number is evenly divisible by x and all #s below x
System.out.println("This program finds the smallest positive "
+ "number that");
System.out.println("is evenly divisible by all of the numbers "
+ "from 1 to N.");
System.out.print("Enter N: ");
int N=kb.nextInt();
long bigN=1;
for(int i=1;i<=N;i++){
bigN=bigN*i;
/*bigN serves as a definite end for our loop
when trying to find all #s divisible from 1 to n
*/
}
long smallestAnswer=bigN;
int count=0;
for(long i=1;i<=bigN;i++){//# being tested
for(int j=1;j<=N;j++){//test
if(i%j==0){
count++;
}
if(count==N && i<smallestAnswer){
smallestAnswer=i;//should catch only the first/smallest answer
break;
}
}
count=0;
}
System.out.printf("\nThe smallest # evenly divisible by all of the "
+ "numbers from 1 to N");
System.out.printf("\nis %,d\n",smallestAnswer);
}
The code works. No run/compileTime errors. It's just far too slow. If the user enters a # bigger than 11, the code just freezes basically
You are using a brute-force algorithm. Challenges, like found on Project Euler, are more often challenges to find the right algorithm, not merely challenges to write the code.
The challenge here is to find the least common multiple (see Wikipedia), of all the numbers from 1 to X.
Example: If X is 10, one way to solve it is to identify the divisors:
1 = 1
2 = 2
3 = 3
4 = 2^2
5 = 5
6 = 2 * 3
7 = 7
8 = 2^3
9 = 3^2
10 = 2 * 5
The divisors for the least common multiple is therefore:
1 * 2^3 * 3^2 * 5 * 7 = 1 * 8 * 9 * 5 * 7 = 2520
Since this is a challenge for you to solve, I'll leave the coding to you.
I'm not quite sure why you're struggling with performance.
$ date && X 20 && date
Tue Jun 25 13:18:13 CDT 2019
N: 20
232792560 is divisible by all numbers 1 to 20
Tue Jun 25 13:18:16 CDT 2019
3 seconds for N == 20.
You are doing extra math for each number you check -- a LOT of extra math. Instead of doing the check for each number 1 to N, first, you could do from 2 to N, as all numbers are divisible by 1. But more importantly, you're doing ALL even if one fails. If you turn that portion around, breaking out of your "does this number work" code as soon as a modulus check fails. On N=20, this will save you 18 checks on all odd numbers.
You could also gain more improvements. The number must be even. So if n>1, you could start at 2 and increment by 2 instead of one. If n>=3, you could actually start at 6 and increment by 6, saving a LOT of math. And if n>=4, you could start at 12 and increment by 12.
For reference, here is my implementation.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv) {
int n = atoi(argv[1]);
long trying = 1;
bool found = false;
while(!found) {
found = true;
++trying;
for (long checkDivide = 2; checkDivide <= n; +checkDivide) {
if (trying % checkDivide != 0) {
found = false;
break;
}
}
}
printf("%ld is divisible by all numbers 1 to %d\n", trying, n);
return 0;
}
I skipped asking for input and just put the value on the command line.
Note that reversing the check also is probably more efficient. That is, start checking at n and work down to 2. X % 20 is going to fail more often than X % 2. I'm not using sufficient time check resolution to be sure how much more efficient it is.
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');
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);
I need to do a MOD of a number which is a long datatype with 1965.
Something like this -
number % 1965
Will the above modulus result always be within 0 and 1964?
Or there are some cases in which it won't return any number between 0 and 1664?
I am using Java as programming language and I will be running my program on Ubuntu machines.
Initially I thought its a Math question but it depends mostly on the Compiler and Language... So kind of confused it will always return number between 0 and 1664 or there are some exception cases?
This is what I have in my method -
private static int getPartitionNumber() {
return (int) (number % 1965);
}
UPDATE:
One thing I forgot to mention is, here number will always be positive number. Any negative number I am throwing IllegalArgumentException at the starting of the program.
No, java's implementation of modulus will return a value in the range (-n, n) for the value x % n. I.e. If you have a negative number as the left operand, then the result will be negative. to get around this, try something like the following:
((x % n) + n) % n;
Which will return a value in the range [0,n)
EDIT (to reflect UPDATE in question)
In the case of positive numbers in the left operand, then simply x % n will produce numbers in the range [0,n) where x >= 0.
I am writing a program which I found on a coding competition website, I have sort of figured out how to solve the problem but, I am stuck on a math part of it, I am completely diluting the problem and showing what I need.
first I need to check if a number is part of a sequence, my sequence is 2*a+1 where a is the previous element in the sequence or 2^n-1 to get nth item in the sequence. so it is 1,3,7,15,31,63...
I don't really want to create the whole sequence and check if a number is present, but I am not sure what a quicker method to do this would be.
Second if I am given a number lets say 25, I want to figure out the next highest number in my sequence to this number. So for 25 it would be 31 and for 47 it would be 63, for 8 it would be 13.
How can i do these things without creating the whole sequence.
I have seen similar questions here with different sequences but I am still not sure how to solve this
Start by finding the explicit formula for any term in your sequence. I'm too lazy to write out a proof, so just add 1 to each term in your sequence:
1 + 1 = 2
3 + 1 = 4
7 + 1 = 8
15 + 1 = 16
31 + 1 = 32
63 + 1 = 64
...
You can clearly see that a_n = 2^n - 1.
To check if a particular number is in your sequence, assume that it is:
x = 2^n - 1
x + 1 = 2^n
From Wikipedia:
The binary representation of integers makes it possible to apply a
very fast test to determine whether a given positive integer x is a
power of two:
positive x is a power of two ⇔ (x & (x − 1)) equals to zero.
So to check, just do:
bool in_sequence(int n) {
return ((n + 1) & n) == 0;
}
As #Blender already pointed out your sequence is essentially 2^n - 1, you can use this trick if you use integer format to store it:
boolean inSequence(int value) {
for (int i = 0x7FFF; i != 0; i >>>= 1) {
if (value == i) {
return true;
}
}
return false;
}
Note that for every elements in your sequence, its binary representation will be lots of 0s and then lots of 1s.
For example, 7 in binary is 0000000000000000000000000000111 and 63 in binary is 0000000000000000000000000111111.
This solution starts from 01111111111111111111111111111111 and use an unsigned bitshift, then compare if it is equal to your value.
Nice and simple.
How to find the next higher number :
For example, we get 19 ( 10011 ) , should return 31 (11111)
int findNext(int n){
if(n == 0) return 1;
int ret = 2; // start from 10
while( (n>>1) > 0){ // end with 100000
ret<<1;
}
return ret-1;
}