Programmer vs. Computer Time

I’ve always been predominantly a C programmer, mainly simply from habit. However, recent projects using Perl have me thinking about the tradeoffs involved. The big issue seems to be time – both at the programmer’s end and at the computer’s.

C compared to languages like Java or Perl generally offers greater flexibility and performance. On the flip side, it makes programming tasks more complex and debugging more difficult. C requires more time from the programmer, in order to minimize time spent running on the computer. Higher-level languages on the other hand, require less from the programmer, at the expense of longer run-time.

Continue reading

C – not a good starting language

In most computer science programs, the first course in the sequence is a basic programming course. Usually, this course introduces the standard concepts, along with one of the more common programming language. And at least from what I’ve seen, that language is usually C.

From what I’ve seen in the classes I’ve taken, and particularly from what I’ve seen tutoring at the college this quarter, this is a mistake. Don’t get me wrong, C is a great programming language. I learned on it. I like it. I use it regularly. But as a first programming language for beginning students it leaves a lot to be desired.

Continue reading

Finding Memory Errors in C

Memory errors are among the nastier programming mistake one can make when using C. Unlike syntax errors, the compiler doesn’t flag them for you. Unlike basic logic errors, you won’t necessarily see the problem in the output. The result – silent data corruption – usually manifests itself differently under different systems and compilers which makes it especially obnoxious to deal with.

Fortunately, there are a couple of good tools for debugging memory errors. My favorite is valgrind, a memory debugger modeled after Rational’s purify (the commercial standard) that runs on Linux and now (experimentally) on MacOS X.

Continue reading

Compile time, over time

I’ve been getting the impression for a while that the GCC C Compiler has been getting slower over time at compiling. To check whether this was in fact true, I timed building a popular software package (emacs) with each major version of the compiler that I could get ahold of. I also added in a few other compilers, for reference.

For the benchmark, I built the temacs part of the GNU emacs distribution (version 22.3). System used is a 1.6GHZ AMD Sempron, 512MB RAM, running Fedora 13.

The compilers used were:

  • gcc – The GNU C Compiler – the standard system compiler on virtually all Linux distributions.
  • llvm – Low-Level Virtual Machine – a new(ish) compiler being developed by Apple and the University of Illinois. It uses the new clang front-end.
  • icc – The Intel C++ Compiler – Intel’s own compiler, known for aggressive optimizations.
  • pcc – The Portable C Compiler – a modernized version of the original BSD Unix system compiler.

Continue reading

Using distcc to speed up Linux builds

distcc is a clever little program that allows you to distribute compilations to many machines, across the network. If you have a bunch of machines running the same operating systems and compilers, it’s quite easy to use: start the daemon on all the machines you wish to serve compilation jobs to, tell the host doing the compiling to use distcc rather than gcc or g++ and compile away!

The problem comes about when the systems aren’t running the same OS. For example: I have an older Linux laptop that I occasionally build things on, but a much faster MacOS X desktop machine. The solution in this case is a cross-compiler. A full-fledged cross-compiler is a complicated thing and requires an obnoxious amount of preparation, but for the purposes of distcc, one can avoid most of the headache.

Continue reading

The 3n + 1 problem

The 3n + 1 problem is deceptively simple. Consider a function f(n) and a sequence ai where:

f(n) = 3n+1 where n is odd
  n/2 where n is even

ai = n where i = 0
  f(ai-1) where i > 1

The Collatz conjecture states that ai will become 1 for some i regardless of what value of n is chosen initially. It remains to date a conjecture as there is no proof for it, but there is no counterexample either.

Continue reading

A small 64-bit conundrum

Traditionally, 64-bit computing is a mixed bag. You gain additional precision and the ability to address more memory, but in many cases those advantages are outweighed by the fact that the 64-bit code requires more memory and cache and the actual individual operations are slower.

X86-64 is somewhat different in this respect, because when AMD took it upon themselves to add 64-bit capabilities to x86, they also made other enhancements including, notably, doubling the number of general purpose registers from a paltry 8 to a more manageable 16. The caveat is that only 64-bit code can have access to these new registers.

Continue reading

Finding primes – simple assembly benchmark

Finding a list of prime numbers is one of those benchmarks that’s pretty easy to code in any language. The trial division method won’t win any prizes for speed or creativity, but it’s a decent test of some basic hardware operations. Having written just such a prime checking programming in C, I was anxious to see whether a hand-coded assembly version would be any faster.

The short answer is that in my implementation, the 64-bit assembly version ran modestly faster on my machine (64-bit Intel Core i7) than the C code compiled in 64-bit mode with full optimizations. Note that this program simply spits out the total number of primes between 2 and MAX, not the actually primes themselves (often a rather long list).

x86 assembly– written for nasm, should run on Linux and MacOS X

C code – should run anywhere

Continue reading

Mersenne Primes – part 1

Mersenne primes are prime numbers of the form 2^n – 1. They were named after Marin Mersenne, a 17th century French monk who compiled a table of the first dozen (although it turns out he got the last few wrong).

The first few are:
3 = 2^2 – 1
7 = 2^3 – 1
31 = 2^5 – 1
127 = 2^7 – 1
8191 = 2^13 – 1
131071 = 2^17 – 1

Continue reading