views:

3007

answers:

7

Hello

I am following "The Art and Science of Java" book and it shows how to calculate a leap year. The book uses ACM Java Task Force's library.

Here is the code the books uses:

import acm.program.*;

public class LeapYear extends ConsoleProgram {
    public void run()
    {

        println("This program calculates leap year.");
        int year = readInt("Enter the year: ");     

        boolean isLeapYear = ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0));

        if (isLeapYear)
        {
            println(year + " is a leap year.");
        } else
            println(year + " is not a leap year.");
    }

}

Now, this is how I calculated the leap year.

import acm.program.*;

public class LeapYear extends ConsoleProgram {
    public void run()
    {

        println("This program calculates leap year.");
        int year = readInt("Enter the year: ");

        if ((year % 4 == 0) && year % 100 != 0)
        {
            println(year + " is a leap year.");
        }
        else if ((year % 4 == 0) && (year % 100 == 0) && (year % 400 == 0))
        {
            println(year + " is a leap year.");
        }
        else
        {
            println(year + " is not a leap year.");
        }
    }
}

Is there anything wrong with my code or should i use the one provided by the book ?

EDIT :: Both of the above code works fine, What i want to ask is which code is the best way to calculate the leap year.

A: 

Why don't you try to input 2004, 2000 and 2100 to test whether the output will be the same?

roddik
The answers are the same. Which code would be the best way to calculate the leap year.
Ibn Saeed
A: 

The pseudo code from Wikipedia looks much simpler:

if year modulo 400 is 0 then leap
 else if year modulo 100 is 0 then no_leap
 else if year modulo 4 is 0 then leap
 else no_leap
Georg
+5  A: 

They look the same to me, though note that this line in your code has some redundancy:

else if ((year % 4 == 0) && (year % 100 == 0) && (year % 400 == 0))

could be replaced by:

else if (year % 400 == 0)

If a number is a multiple of 400 then it's automatically also a multiple of 100 and 4.

therefromhere
Correction, 4, not 4! :)
Sev
Hah corrected to avoid confusion between (!) exclamation and the not operator ;)
therefromhere
@OP, once you make this modification, the "books" code as you put it and your code will become functionally identical.
Sev
@therefromhere, I was more "concerned" about the confusion between exclamation and 4! (4 factorial)
Sev
@Sev, you are correct :).
Ibn Saeed
Which code is much more practical, the one used by the author or the one written by me. ? Should I follow the author's way ?
Ibn Saeed
+4  A: 

I suggest you put this code into a method and create a unit test.

public static boolean isLeapYear(int year) {
    assert year >= 1583; // not valid before this date.
    return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}

In the unit test

assertTrue(isLeapYear(2000));
assertTrue(isLeapYear(1904));
assertFalse(isLeapYear(1900));
assertFalse(isLeapYear(1901));
Peter Lawrey
Thanks, im only a beginner in Java Programming. I havent learned Unit Testing as yet. But thanks for the answer :)
Ibn Saeed
If I were a lecturer, I'd teach unit testing first. In maths and engineering maths classes, it's normal practice to put the results back through the formulas to check them; unit testing is getting the computer to do the same thing for your program.
Pete Kirkham
Im following Standfords Programming Methodology Video course, the lecturer is using The Art and Science of Java book to teach the methodology of programming rather than teach Java. Im on chapter 4 and still there is no topic on Unit Testing so far.
Ibn Saeed
+2  A: 

It's almost always wrong to have repetition in software. In any engineering discipline, form should follow function, and you have three branches for something which has two possible paths - it's either a leap year or not.

The mechanism which has the test on one line doesn't have that issue, but generally it would be better to separate the test into a function which takes an int representing a year and returns a boolean representing whether or not the year is a leap year. That way you can do something with it other that print to standard output on the console, and can more easily test it.

In code which is known to exceed its performance budget, it's usual to arrange the tests so that they are not redundant and perform the tests in an order which returns early. The wikipedia example does this - for most years you have to calculate modulo 400,100 and 4, but for a few you only need modulo 400 or 400 and 100. This is a small optimisation in terms of performance ( at best, only one in a hundred inputs are effected ), but it also means the code has less repetition, and there's less for the programmer to type in.

Pete Kirkham
Thanks, your answer makes sense.
Ibn Saeed
+1  A: 

The correct implementation is:

public static boolean isLeapYear(int year) {
  Calendar cal = Calendar.getInstance();
  cal.set(Calendar.YEAR, year);
  return cal.getActualMaximum(DAY_OF_YEAR) > 365;
}

But if you are going to reinvent this wheel then:

public static boolean isLeapYear(int year) {
  if (year % 4 != 0) {
    return false;
  } else if (year % 400 == 0) {
    return true;
  } else if (year % 100 == 0) {
    return false;
  } else {
    return true;
  }
}
cletus
+1 for using library code. I would suggestion adding a note on it is because that 400 is a multiplum of 100 that you test for 400 before 100 as opposed to the original code.
Thorbjørn Ravn Andersen
A: 

Pseudo code from Wikipedia translated into the most compact Javaese...

(year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0))

The Sphinc