Calculating the factorial of a number in Delphi: Recursive and iterative methods

The factorial function can be defined in both recursive and iterative ways. Take a look at the following definitions borrowed from Wikipedia.

Recursive definition:

Factorial Recursive definition







Iterative definition:

Factorial Iterative Definition





For both the above definitions we have that:

Zero Factorial



The purpose here is not the mathematical stuff, but two provide the implementation of such definitions in Delphi (Object Pascal).

First, I bring you one recursive implementation of the factorial function. Notice how the function calls itself, which is what the recursion really is:

function Factorial(aNumber: Integer):
Integer;
begin
 
if aNumber < 0 then
    raise Exception.Create('
The factorial function is not
  defined for negative integers.
');

 
Result:= 1;
  if aNumber > 0 then
    Result:= Factorial(aNumber-1) * aNumber;
end;

Second, I present you one iterative implementation of the factorial function. You can easily see the iteration performed in the “for” loop below:

function Factorial(aNumber:
Integer): Integer;
var
  i: Integer;
begin
  if aNumber < 0 then
    raise Exception.Create('
The factorial function is not
  defined for negative integers.
');

  Result:= 1;
  for i:=1 to aNumber do
    Result:= Result * i;
end;


Big-O considerations:
The recursive factorial function implemented before has a linear growth O(n), not O (n!). In addition, the iterative factorial function is also linear
O(n).

Submit Blogger sitemap to Google, Yahoo and Bing

Sitemaps let search engines to know more about the structure of your website. Blogs, like any other websites, can improve their visibility on the Internet, by adding their XML sitemaps to the major search engines (Google, Yahoo and Bing).

The problem with Blogger is that you can’t upload your own sitemap or any other file to your blogspot sub-domain root (ex. http://sub-domain.blogspot.com/) or custom domain root (ex. http://www.yanniel.info/).

No panic! There’s a workaround for this: luckily for bloggers, sitemaps can be generated as feeds; meaning that you can actually submit an RSS or Atom feed as a valid sitemap.

Blogger supports both RSS and Atom formats. Anyway, I advice you use the Atom feed URL, because I have had problems when submitting the RSS URL. What problems?  Well, I don’t recall now, but I’m pretty sure I had problems ;-)

Here is the Atom sitemap URL for Blogger (it does work for both blogspot sub-domain and custom domains):

http://sub-domain.blogspot.com/atom.xml?redirect=false&start-index=1&max-results=500

http://www. customdomain/atom.xml?redirect=false&start-index=1&max-results=500

Basically, the important part is:

atom.xml?redirect=false&start-index=1&max-results=500

A brief explanation:
  • atom.xml express the fact that you are requesting an XML Atom feed.
  • redirect=false prevents  Blogger from redirecting your sitemap to a third-party sitemap burner. This is very useful if you are using FeedBurner, because FeedBurner feeds are not recognized as valid sitemaps in most cases.
  • start-index=1 indicates that you want to syndicate starting on your first post. If you chose 10, for instance, your sitemap will start at post number 10.
  • max-results=500 tells Blogger to include 500 posts in your sitemap.  You can change this number as well, but the maximum count of posts syndicated in your feed will never exceed 500.
So, what happens if my blog has more than 500 posts? Well, you simply add a second sitemap, a third and so on. See the URLs:

http://sub-domain.blogspot.com/atom.xml?redirect=false&start-index=1&max-results=500

http://sub-domain.blogspot.com/atom.xml?redirect=false&start-index=501&max-results=500

http://sub-domain.blogspot.com/atom.xml?redirect=false&start-index=1001&max-results=500
................................................

There’s only one thing pending: you need to add your sitemaps to the major search engines…
Submitting your sitemaps for each search engine is a slightly different process. I might cover those SEO topics in future posts.

Fetching a web page with Delphi

This function fetches the HTML content of a given web page. It takes the page's URL as parameter and returns the corresponding HTML text. The name CURL comes from the PHP Client URL Library that can be used (among other things) for the same purpose.
.................
implementation

uses
  IdHTTP;

function Curl(aURL: string): string;
const
  cUSER_AGENT = 'Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)';
var
  IdHTTP: TIdHTTP;
  Stream: TStringStream;
begin
  Result := '';
  IdHTTP := TIdHTTP.Create(nil);
  Stream := TStringStream.Create;
  try
    IdHTTP.Request.UserAgent := cUSER_AGENT;
    try
      IdHTTP.Get(aURL, Stream);
      Result := Stream.DataString;
    except
      Result := '';
    end;
  finally
    Stream.Free;
    IdHTTP.Free;
  end;
end;
.................

You can modify this routine to have the web page saved to a file instead. For that, you only need to use the TStringStream.SaveToFile method in substitution of TStringStream.DataString.

One final observation: you may change the cUSER_AGENT constant to whatever value you decide. If you don’t specify a user agent, then a default value will be provided.

Ah! Don’t forget to add IdHTTP to the uses clause!

String compression/decompression routines using Delphi

I wrote the following two functions (in bold) with the purpose of compressing/decompressing string values within a Delphi application:

.........................
implementation

uses
  ZLib;

function ZCompressString(aText: string; aCompressionLevel: TZCompressionLevel): string;
var
  strInput,
  strOutput: TStringStream;
  Zipper: TZCompressionStream;
begin
  Result:= '';
  strInput:= TStringStream.Create(aText);
  strOutput:= TStringStream.Create;
  try
    Zipper:= TZCompressionStream.Create(strOutput, aCompressionLevel);
    try
      Zipper.CopyFrom(strInput, strInput.Size);
    finally
      Zipper.Free;
    end;
    Result:= strOutput.DataString;
  finally
    strInput.Free;
    strOutput.Free;
  end;
end;

function ZDecompressString(aText: string): string;
var
  strInput,
  strOutput: TStringStream;
  Unzipper: TZDecompressionStream;
begin
  Result:= '';
  strInput:= TStringStream.Create(aText);
  strOutput:= TStringStream.Create;
  try
    Unzipper:= TZDecompressionStream.Create(strInput);
    try
      strOutput.CopyFrom(Unzipper, Unzipper.Size);
    finally
      Unzipper.Free;
    end;
    Result:= strOutput.DataString;
  finally
    strInput.Free;
    strOutput.Free;
  end;
end;

.........................

The main advantage of the above functions over the ZCompressStr and ZDecompressStr routines shipped with ZLib.pas, is that you won’t have potential data lost when handling Unicode <->Ansi conversions. In other words, the above functions will work in both Ansi Delphi versions (previous to Delphi 2009) and Unicode Delphi versions (Delphi 2009, 2010, XE and so on).

Note that you need to include ZLib in the uses clause. ZLib.pas is a high level wrapper to the ZLib library created by Jean-Loup Gailly and Mark Adle for data compression.

In addition, using the TZCompressionStream and TZDecompressionStream classes you can also create (compress) and decompress ZIP files.

What did (do) I need this for? Well, the applicability for data compression is wide...

A real life example? I needed to store JSON strings in a MySQL database. As a way to optimize resources I compressed all JSON strings before the insertion into the database. After the retrieval, I was able to decompress each string to its original value. The compression rate was huge: I packed ~9000 chars in ~300 per JSON on average. This is a considerable saving: my table contains more than one million rows. Do the math yourself! :-)

Delphi Developers in Toronto

There are very little opportunities for Delphi developers in Toronto (Canada). The job market for software developers in this area is monopolized by .NET (C#, VB), Java and C++ in a huge percentage. Objective C, Python, PHP, Ruby are more popular than Delphi around here.

I don’t blame the Torontonian companies for deprecating Delphi. It‘s a reality that after the release of Delphi 7, Borland drove “the once most useful and popular IDE of the world” into a dark era.

Nonetheless, there is hope for Delphi. Lately, it has improved quite a bit, catching up to some degree for the time lost in the Borland's apocalypse. Some important milestones archived by Delphi lately:
  • Unicode support.
  • 64 Bits support.
  •  Mufti-platform support (with the introduction of FireMonkey)
Finally, I would like to list a few companies using Delphi these days in Toronto (Greater Toronto Area) :