Radix sort revisited

Around a year and a half ago I wrote an article on the perils of relying on big-O notation, and in it I focused on a comparison between comparison-based sorting (via std::sort) and radix sort, based on the common bucketing approach.

Recently I came across a video on radix sort which presents an alternate counting-based implementation at the end, and claims that the tradeoff point between radix and comparison sort comes much sooner. My intuition said that even counting-based radix sort would still be slower than a comparison sort for any meaningful input size, but it’s always good to test one’s intuitions.

So, hey, it turns out I was wrong about something. (But my greater point still stands.)

Read more…

The danger of big-O notation

A common pitfall I see programmers run into is putting way too much stock into Big O notation and using it as a rough analog for overall performance. It’s important to understand what the Big O represents, and what it doesn’t, before deciding to optimize an algorithm based purely on the runtime complexity.

Read more…

#pragma once vs. #ifndef/#define

After getting in an extended discussion about the supposed performance tradeoff between #pragma once and #ifndef guards vs. the argument of correctness or not (I was taking the side of #pragma once based on some relatively recent indoctrination to that end), I decided to finally test the theory that #pragma once is faster because the compiler doesn’t have to try to re-#include a file that had already been included.

For the test, I automatically generated 500 header files with complex interdependencies, and had a .c file that #includes them all. I ran the test three ways, once with just #ifndef, once with just #pragma once, and once with both. I performed the test on a fairly modern system (a 2014 MacBook Pro running OSX, using XCode’s bundled Clang, with the internal SSD).

Read more…

Exceptions vs. error returns, quantified

Today I got into a discussion regarding embedded programmers and their tendency to avoid exceptions in C++ (even after moving to new-school “embedded” systems such as smartphones, game consoles, and set-top boxes). The argument basically boils down to three things: code size, memory usage, and execution speed. So, rather than continue on without actually putting my beliefs to the test (the discussion basically centered around whether engineers are making assumptions based on how things were 15+ years ago), I decided to construct a minimal test which I think shows where the tradeoffs may be.

Note: The timing and memory analysis has been updated as of May 24, 2018.

Read more…