PERL

Project Euler, Problem 2

I've got problem #2 in the bag.

Problem #2 goes like this:
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

Find the sum of all the even-valued terms in the sequence which do not exceed four million.

And my code goes as follows:
Haskell:

  1. --fibinaci :: (Num a) => a -> a -> [a]
  2. fibinaci a b
  3. | sum' > 4000000 = []
  4. | otherwise = sum' : fibinaci b sum'
  5. where sum' = a + b
  6.  
  7. problem2 = sum $ filter (even) (fibinaci 0 1)

Python:
  1. #!/usr/bin/python
  2.  
  3. def fibinaci_list( in_list, input1, input2):
  4. flip = True
  5. while ( input1 + input2 < 4000000):
  6. if( flip == True):
  7. input1 = input1 + input2
  8. in_list.append(input1)
  9. flip = False
  10. else:
  11. input2 = input1 + input2
  12. in_list.append(input2)
  13. flip = True
  14.  
  15. def even(n):
  16. if n % 2 == 0:
  17. return True
  18. else:
  19. return False
  20.  
  21.  
  22. def main():
  23. first_list = []
  24. fibinaci_list(first_list, 0, 1)
  25. second_list = filter(even, first_list)
  26. print "%s" % (sum(second_list))
  27.  
  28. if __name__ == "__main__":
  29. main()

And finally, Perl:
  1. #!/usr/bin/perl
  2.  
  3. my $total = 0;
  4. my $count1 = 0;
  5. my $count2 = 1;
  6. my $flip = 1;
  7.  
  8. while( $count2 + $count1 < 4000000)
  9. {
  10. if ( $flip == 1)
  11. {
  12. $count1 += $count2;
  13. if ( $count1 % 2 == 0)
  14. {
  15. $total += $count1;
  16. }
  17. $flip = 0;
  18. }
  19. else
  20. {
  21. $count2 += $count1;
  22. if ( $count2 % 2 == 0)
  23. {
  24. $total += $count2;
  25. }
  26. $flip = 1;
  27. }
  28. }
  29.  
  30. print $total;

Originally, I tried to copy the Python algorithm to Perl, using an array instead of a list. That didn't work. The program would always fail due to out of memory errors. To solve this problem I changed the program to work without using arrays and just took the whole fibinaci function out and put it into main.

As always, constructive comments for the code are welcomed.

Project Euler: Problem 1

So I'll admit it, I'm more than acceptably late to this party. OJ started working on these problems years ago, while I was still coding away on other stuff at school. Now that I'm not in school and needing a challenge I'm doing the best I can to tackle the problems at Project Euler. Since I'm also trying to pick up Haskell, this makes for a good way to learn the language. This isn't my first time using a Functional Programming language. But the last time I tried, it was forced upon me at school with inadequate assistance and the whole experience left a bad taste in my mouth. I'm glad that getting over the bad experience and learning something new at the same time.

I've started keeping a github repo with my solutions for the various problems. If anyone is interested in commenting on my code please do so. I welcome all constructive criticism.

To start this thing off; problem one reads,
“If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find the sum of all the multiples of 3 or 5 below 1000.”

Being this one was simple. I coded it up in Haskell, Python, and Perl.
Haskell:

  1. problem1 = sum $ filter (\x -> mod x 3 == 0 || mod x 5 == 0) [1..1000]
  2. problem1' = sum $ filter (\x -> mod x 3 == 0 || mod x 5 == 0) [1..999]

Python:
  1. #!/usr/bin/python
  2.  
  3. def threeorfive(n):
  4. if ( n % 3 == 0 or n % 5 == 0):
  5. return True
  6. else:
  7. return False
  8.  
  9. def main():
  10. first_list = range(1,1000)
  11. second_list = filter(threeorfive, first_list)
  12. print "%s" % (sum(second_list))
  13.  
  14. if __name__ == "__main__":
  15. main()

Perl:
  1. #!/usr/bin/perl
  2.  
  3. my $count = 0;
  4. my $total = 0;
  5.  
  6. while ( $count < 1000)
  7. {
  8. if ( $count % 3 == 0 or $count % 5 == 0)
  9. {
  10. $total += $count;
  11. }
  12.  
  13. $count++;
  14. }
  15.  
  16. print $total;

One thing that is nice about doing this in different languages, is that you get to become aware of the differences between some of those languages. For instance in Python the range function works a little differently than I expected. I was expecting an inclusive range function, one in which the 10 is included in the list. But that is now how Python's range works. It gives me 10 numbers, starting with 1, the end result is a list ending in 9. It's not a big deal and easily fixable, but just not something I was expecting. That is why the Haskell code has to functions in it. Just to verify that the Python code was correct.

I'll be posting more answers as I complete them. So expect to see some random posts with Euler solutions in them.

Getting all installed software, and their versions, on Debian/Ubuntu pt 2: Now with Threads!

Even though Poisonbit's solution to the original problem is the fastest (Thanks again PoisenBit!) I decided to use the original code as an excuse to learn multi-threading programming in PERL and see if it might improve the performance of the original code. One of those "for shits and giggles" moments.

First off, here is the new and improved code:

  1. #!/usr/bin/perl
  2. #######################################################################
  3. # Created By: Bryce Verdier
  4. # on 4/14/10
  5. #
  6. # Function: grab all installed packages, using threads
  7. # find their exact versions, and display them
  8. # NOTE: FOR USE ON DEBIAN BASED MACHINES
  9. #######################################################################
  10.  
  11. use threads;
  12.  
  13. my $temp_pack;
  14. my $temp_ver;
  15. my $returned_version;
  16. my %pack_hash :shared;
  17. my $thread_count = 0;
  18. my $pack_count;
  19. my @return = `dpkg --get-selections`;
  20.  
  21. sub get_package_ver
  22. {
  23. my %args = @_;
  24. my $temp_ver;
  25. my $returned_ver = `dpkg -s $args{package}`;
  26.  
  27. $returned_ver =~ m/^Version: (.+)$/m;
  28.  
  29. $temp_ver = $1;
  30.  
  31. lock($args{hash});
  32. $args{hash}{$args{package}} = $temp_ver;
  33. }
  34.  
  35. foreach (@return)
  36. {
  37. $_ =~ m/^(\S+)[ \t].*/;
  38.  
  39. $_ = $1;
  40. }
  41.  
  42.  
  43. $pack_count = @return;
  44. while ( $pack_count - $thread_count >= 1)
  45. {
  46. my $th1 = threads->create(\&get_package_ver, hash => \%pack_hash,
  47. package => $return[$thread_count]);
  48. my $th2 = threads->create(\&get_package_ver, hash => \%pack_hash,
  49. package => $return[$thread_count+1]);
  50.  
  51. $th1->join();
  52. $th2->join();
  53.  
  54. $thread_count = $thread_count + 2;
  55. }
  56.  
  57. # Get the odd package, if there is one
  58. if ($pack_count - $thread_count == 1)
  59. {
  60. my $th1 = threads->create(\&get_package_ver, hash => \%pack_hash,
  61. package => $return[$thread_count]);
  62.  
  63. $th1->join();
  64.  
  65. $thread_count++;
  66. }
  67.  
  68. while((my $key, my $value) = each(%pack_hash))
  69. {
  70. print "$key : $value\n";
  71. }

For all the number crunchers out there, putting things into two threads reduced the program execution time by more than 1 minute. For a program that took two and a half seconds to complete, a reduction to one and a half seconds is pretty significant.Well, in my book anyway.

After first following the suggestions of Sam for the regexes, (Thanks again Sam!) I pulled out the version checking code into its own function so that each thread would have a very specific thing to do. After that I realized I needed to clean up the package names that were being sent to the threads, creating the foreach loop on line 35. Within the foreach loop I tried something that I didn't expect to work - the line:

$_ = $1;

There isn't a reason for the line above to not work, but in the PERL code I've seen "$_" is not being used as a pointer to write data to, only to retrieve data from. And I guess that is why I did not expect it to work. But then, that's why I'm doing this - to learn things. :-D

After these changes and adding the threads code, I was almost done. For some reason the data from each thread wasn't getting stored into the hash. It wasn't until I looked a little deeper at the examples on perldoc that I saw what I needed to do. In the section "Shared And Unshared Data" I noticed I needed to mark %pack_hash as shared, so all the threads could access it. Which I did like so:

my %pack_hash :shared;

All in all, my first multi-threading coding expirence in perl wasn't bad. Granted the program isn't complicated, but this was truely new territory for me. I haven't tried doing any kind of multi-process/multi-threading programming since my operating systems class almost 3 years ago, so there were some battles to fight in my head on how to modify things to work with multiple threads. But again, it was a good experience. And I'm going to reiterate this so everyone remembers: don't use this code in production. Poisonbit's solution is MUCH faster than mine. Like me, use this code for learning.

Getting all installed software, and their versions, on Debian/Ubuntu

AAAHHH work! Everyone has those horror stories where your boss, or the client, comes and asks for some horrible feature that will require an entire rewrite of the program. Fortunately, that hasn't happened to me (yet) and that is not what this blog entry is about. It's about the even more (what I believe to be) unlikely scenario when someone wants a feature that they think will be difficult to create and after some research you implement that feature in a small amount of time. It's a rare event and great confidence booster when it does happen though.

A co-worker wanted a feature added to a project. He thought that it might take a while to complete so he talked to me first about it to “plant the seed” and get my brain started on figuring out a solution, not expecting a quick turnaround. Of course, as the title hints at, the problem was to find out all the packages installed on our Debian boxes as well as their version numbers. So after a little bit of googleing and man page reading I had a basic algorithm to build on. Twenty minutes of coding and testing later, I had this script:

  1. #!/usr/bin/perl
  2. #######################################################################
  3. # Created By: Bryce Verdier
  4. # on 4/14/10
  5. #
  6. # Function: grab all installed packages, find their exact
  7. # versions, and display them
  8. # NOTE: FOR USE ON DEBIAN BASED MACHINES
  9. #######################################################################
  10.  
  11. my $temp_pack;
  12. my $temp_ver;
  13. my $returned_version;
  14. my %pack_hash;
  15. my @return = `dpkg --get-selections`;
  16.  
  17. foreach (@return)
  18. {
  19. $_ =~ m/(\S*)[ \t].*/i;
  20.  
  21. $temp_pack = $1;
  22.  
  23. $returned_version = `dpkg -s $temp_pack`;
  24.  
  25. $returned_version =~ m/Version: (.*)/i;
  26.  
  27. $temp_ver = $1;
  28.  
  29. $pack_hash{$temp_pack} = $temp_ver;
  30.  
  31. }
  32.  
  33. while((my $key, my $value) = each(%pack_hash))
  34. {
  35. print "$key : $value\n";
  36. }

I will admit that is a little slow (on my desktop it takes around two and a half minutes to complete) and could probably benefit from some parallelization. However, that might be over-engineering for such a simple task. I'll code that feature up next, grab a stopwatch, and test it just to find out. Anybody gonna place bets one way or another? In the meantime, I'm proud of my use of regex's in this script, the "\S" removes the trailing whitespace from the package names, instead of just using ".*", which should speed things up a bit because I don't have to call chomp on each package name. Also using a hash for storage simplifies the data management and should allow for an easier time porting the code into a larger script later.

Syndicate content