Reputation: 163
Assuming, you have year a and year b, which are the range of years (they are included), how to properly count leap years in this range without using loops? (gregorian calendar)
I wrote this on C#, but i don't think that my code is great. I also used a global variable, but lol, i think there are a solution that is so much better and more elegant than this. I'm just a newbie, so sorry that i'm asking this dumb question. Also, i don't think you should use DateTime here and etc.
Here's my code:
class Program
{
public static int leap_years = 0;
static void Main()
{
do
{
int a, b;
leap_years = 0;
do Console.Write("Enter a: ");
while (!int.TryParse(Console.ReadLine(), out a) || a < 0);
do Console.Write("Enter b: ");
while (!int.TryParse(Console.ReadLine(), out b) || b < 0 || a == b || a >= b);
Console.WriteLine("Leap years: " + countLeapYears(a, b));
} while (Console.ReadKey().Key != ConsoleKey.Escape);
}
Where countLeapYears
is
static public int countLeapYears(int a, int b)
{
if (a > b)
return leap_years;
else
{
if (a % 4 == 0)
{
if (a % 100 == 0)
{
if (a % 400 == 0)
{
Console.WriteLine("Year {0} - leap year", a);
leap_years++;
a += 4;
countLeapYears(a, b);
}
else
{
Console.WriteLine("Year {0} - not a leap year", a);
a++;
countLeapYears(a, b);
}
}
else
{
Console.WriteLine("Year {0} - leap year", a);
leap_years++;
a += 4;
countLeapYears(a, b);
}
}
else
{
Console.WriteLine("Year {0} - not a leap year", a);
a++;
countLeapYears(a, b);
}
}
return leap_years;
}
}
Upvotes: 2
Views: 1057
Reputation: 186803
Well, we don't have year 0
: 1BC
is followed by 1AD
which spoils the fun. However, if we can work with AD
(positive years) only, you can try something like this:
private static int countLeapYears(int from, int to) =>
(to / 4 - (from - 1) / 4) -
(to / 100 - (from - 1) / 100) +
(to / 400 - (from - 1) / 400);
Let's test it with respect to naive computation:
private static int naiveCount(int from, int to) {
int result = 0;
for (int i = from; i <= to; ++i)
if (i % 400 == 0 || i % 4 == 0 && i % 100 != 0)
result += 1;
return result;
}
...
Random gen = new Random(123);
var result = Enumerable
.Range(1, 20)
.Select(i => {
int to = gen.Next(1590, 2222);
int from = gen.Next(1590, 2222);
return (from: Math.Min(from, to), to: Math.Max(from, to));
})
.Select(test => $"{test.from} - {test.to} actual: {countLeapYears(test.from, test.to),3} expected: {naiveCount(test.from, test.to),3}");
Console.Write(string.Join(Environment.NewLine, result));
Outcome:
2163 - 2212 actual: 12 expected: 12
2059 - 2102 actual: 10 expected: 10
1620 - 2056 actual: 107 expected: 107
1600 - 1684 actual: 22 expected: 22
1713 - 1988 actual: 67 expected: 67
1902 - 2164 actual: 65 expected: 65
1709 - 1881 actual: 42 expected: 42
1639 - 2124 actual: 118 expected: 118
1751 - 1948 actual: 48 expected: 48
1594 - 2184 actual: 144 expected: 144
1605 - 1691 actual: 21 expected: 21
1591 - 2082 actual: 120 expected: 120
1993 - 2066 actual: 18 expected: 18
2022 - 2158 actual: 33 expected: 33
1678 - 1919 actual: 57 expected: 57
1966 - 2128 actual: 40 expected: 40
1635 - 2069 actual: 106 expected: 106
1649 - 1963 actual: 75 expected: 75
1719 - 2169 actual: 110 expected: 110
1847 - 2093 actual: 61 expected: 61
Upvotes: 1
Reputation: 107
public int LeapYear(int initialYear, int endYear, int ref countYear)
{
if (initialYear > endYear)
{
return countYear;
}
if(DateTime.IsLeapYear(initialYear)
{
countYear++;
}
initialYear++;
LeapYear(initialYear, endYear, countYear)
}
Upvotes: 1