Monday, October 27, 2008

Zeller's Congruence in C#

In "Problems for Computer Solution" by Fred Gruenberger and George Jaffray, one of the problems revolved around determining what day of the week for any date. The algorithm is called Zeller's Congruence.

In this day and age, where finding the day of the week is as simple as DateTime.Now.DayOfWeek programmers may not realize that in the early days of computing it was much more difficult. One way was to code an implementation of Zeller's Congruence. Towards the end of the 19th century, Christian Zeller formulated an algorithm that could calculate the day of the week.

Back in the 60's, second year computer science students used the problem of implementing this algorithm as a semester project. Yet, now even if we do not use the .Net Framework, implementing the algorithm is the work of a few minutes.

The Algorithm:

D = Day of the month
M = Month (With a trick, March is the first month of the year, January and February then being the 11th and 12th month of the previous year)
X = Decade (With a trick - see Month above)
C = Century (With a trick - see Month above)

(int(2.6 * M - 0.2) + D + X + int(X / 4) + int(C / 4) - (2 - C)) modulo 7

One cool trick in the code below is calculating the the month of the year (Including the trick above) using only a math, no logic.

Here it is step by step:

Start with the months as numbers: 1,2,3 ... 11,12
Add 9 to each month: 10,11,12 ... 20,21
Modulo each month by 12 (%): 10,11,0 ... 8,9
Add 1: 11,12,1 ... 9,10

So now we have what we wanted, Jan = 11, Feb = 12, Mar = 1 ... Nov = 9, Dec = 10

Here is the full algorithm:

string[] DaysOfTheWeek =
    {"Sunday", "Monday", "Tuesday",
    "Wednesday", "Thursday", "Friday", "Saturday"};

int Day = DateTime.Now.Day;
int Month = ((DateTime.Now.Month + 9) % 12) + 1;

int YearsInCentury = Month > 10 ?
    (DateTime.Now.Year - 1) % 100 :
    DateTime.Now.Year % 100;

int Century = YearsInCentury == 99 && Month > 10 ?
    (DateTime.Now.Year - 100) / 100 :
    DateTime.Now.Year / 100;

int DayOfWeek = ((((int)((2.6 * (float)Month) - 0.2)
    + Day + YearsInCentury + (YearsInCentury / 4)
    + (Century / 4) - (2 * Century))) % 7);

Console.Write(DaysOfTheWeek[DayOfWeek]);
Console.Read();

Sunday, October 26, 2008

LINQ to the rescue!

If you have ever had multiple data sources that you pull into DataTables, you know that you can use the .Merge function to combine the data. But, what if there are dupicates? What about sorting the merged data?

Well, using LINQ to data, you can use the power of LINQ without needing SQL Server or a database at all, for that matter. Here is a simple example using LINQ to data, to sort and pull only distinct records in the merged DataTable.

static void Main()
{
    var dtFirst = new DataTable();
    var dtSecond = new DataTable();

    dtFirst.Columns.Add("Value", Type.GetType("System.Int32"));
    dtSecond.Columns.Add("Value", Type.GetType("System.Int32"));

    var row = new object[1];

    for (var i = 25; i >= 0; i--)
    {
        row[0] = i;
        dtFirst.Rows.Add(row);
        row[0] = i+5;
        dtSecond.Rows.Add(row);
    }

    dtFirst.Merge(dtSecond);

    IEnumerable MyTable = dtFirst.AsEnumerable();

    var dtLinqData = (from
            MyRow
        in
            MyTable
        orderby
            MyRow.Field("Value")
        ascending
        select
            MyRow.Field("Value")).Distinct().ToArray();

    Console.WriteLine("Original Data");

    foreach (DataRow dr in dtFirst.Rows)
        Console.Write(dr["Value"] + " ");

    Console.WriteLine();
    Console.WriteLine("Linq Data");

    foreach (var dr in dtLinqData)
        Console.Write(dr + " ");

    Console.Read();

}

Thursday, October 23, 2008

Where have all the colors gone?

If you are programming in Silverlight, you probably have seen all the colors available in the XAML. Want a line that is AliceBlue, no problem, but if you want to create the same line programatically in C#, good luck.

The Colors class is just a small subset of all the HTML named colors, so the only way to add AliceBlue is to use Color.FromArgb, so you go out to a website that lists all the colors' RGB values. AliceBlue is #F0F8FF, so you paste the RGB value into Color.FromArgb.

But wait! Color.FromArgb expects 4 bytes, not a single number (The first byte is the Alpha value - i.e. the transparentcy of the color, hence the A in front of the RGB) and our color is only 3 bytes. We can add #FF in front of #F0F8FF but Color.FromArgb expects them to be separate values separated by a comma.

Color.FromArgb(#FF, #F0, #F8, #FF) will not work because C# does not recognize them as numbers. The key to having C# recognize them as hex numbers is to replace the hash(#) with 0x. So AliceBlue is now Color.FromArgb(0xFF, 0xF0, 0xF8, 0xFF).

Too much work you say? I agree. I just want to use my named colors. So, I created my own Color class that in Silverlight will output named colors!

The code looks like this:


private class MyColors
{
    public static Color Aliceblue
    {
        get
        {
            return GenerateColorStruct(0xFFF0F8FF);
        }
    }

    .
    .
    .

    private static Color GenerateColorStruct
                                    (uint color)
    {
        var mask = 0x000000FF;
        var returnval = new Color
        {
            A = ((byte)((color >> 24) & mask)),
            R = ((byte)((color >> 16) & mask)),
            G = ((byte)((color >> 8) & mask)),
            B = ((byte)((color) & mask))
        };

        return returnval;
    }
}


The entire .cs file can be found here. Since this is a private class that you can add to any Silverlight page.cs file that needs named colors , you can also add your own named colors that you want to use all the time!

You can also compile it to its own dll, but I like it better in the page.cs file. For size of outputs sake, right before you publish you can remove all the unused colors.