CSC 482 HW3 — Language Comparison: Final Report

Algorithm: Randomized Quicksort (CLRS Ch. 5, RANDOMIZED-QUICKSORT / RANDOMIZED-PARTITION — Probabilistic Analysis and Randomized Algorithms, the unit's reading). Chosen because it ties directly to the unit content, has a well-known expected running time of O(n log n) to check the empirical curve against, and is simple enough to implement identically (in-place, Lomuto partition, uniformly random pivot swapped in before partitioning) in every language using only each language's standard library or toolchain (Rust's rand crate is the one standard, explicitly-allowed exception, since Rust's standard library has no built-in RNG).

Languages compared (15): C, C++, C#, Java, Python, Rust, Go, JavaScript, TypeScript, F#, Zig, Common Lisp, Pascal, x86-64 Assembly, PHP. The first 7 were the original comparison; the remaining 8 were added in a second round at the student's explicit request to push the comparison further (see §7 for which additional languages were requested but skipped, and why).

Machine: AMD Ryzen 7 5800H (8 cores / 16 threads, ~3.2 GHz base), 32 GB RAM, Windows 11 Pro host. All builds and all timed runs were executed inside WSL2 Ubuntu 26.04 ("Resolute Raccoon") for a consistent Linux environment across every language.

Method: each language has its own agent-implemented, independently-run benchmark under HW3/<lang>/, following the shared protocol in ../DESIGN.md: starting at n=1000, doubling n each iteration, generating a fresh random array each time (generation not timed), timing only the sort call with each language's standard high-resolution clock, and stopping when a single iteration exceeds 4.0s (the condition that actually ended every run here), 25 iterations elapse, or n would exceed 200,000,000. One call per n, no averaging — exactly as the assignment specifies is sufficient for a general trend.


1. Compliance check against HW3.docx

Requirement (from HW3.docx) Status Notes
Pick at least two languages ✅ Exceeded 15 languages (see above)
Single function processing a data set (decomposable into sub-functions) ✅ Randomized Quicksort, decomposed into partition/randomized_partition/randomized_quicksort (or language equivalent) in every implementation
Main loop over n; randomly construct data set of size n each iteration ✅ Every implementation generates a fresh random array/list/vector of size n per iteration, untimed
Call the function and time that call ✅ Each language uses its own high-resolution monotonic timer around the sort call only
Determine a reasonable starting n; repeat enough to get interesting results ✅ n starts at 1000; 12–17 iterations per language (PHP: 14, Python: 12, TypeScript: 16, everyone else: 17)
Increase n by an appropriate amount each iteration ✅ n *= 2 every iteration, exactly one of the assignment's suggested schemes
Print or log results ✅ Every language prints to stdout live and writes results/<lang>.csv
One function call per n (no averaging required) ✅ Exactly one timed call per n in every language
Repeat for every language ✅ All 15
Nicely formatted line graph, time on y-axis, n on x-axis, all languages on one graph ✅ results/combined_plot.png (linear axes, as literally requested), a results/combined_plot_loglog.png for readability across the huge n range, and a bonus results/combined_plot_compiled_zoom.png zooming in on the tightly-clustered native-compiled languages
Note the CPU used ✅ AMD Ryzen 7 5800H, see above and every per-language report
Does the curve match expected asymptotic efficiency? ✅ Discussed below and in each reports/<lang>_report.md
Cite source of any code grabbed from the internet ✅ Every implementation is original, based on CLRS's published RANDOMIZED-QUICKSORT/RANDOMIZED-PARTITION pseudocode (Cormen, Leiserson, Rivest & Stein, Introduction to Algorithms, Ch. 5) — cited in every report. Rust additionally cites the rand crate (https://crates.io/crates/rand); Assembly cites the specific libc functions it links against (printf, rand, clock_gettime, etc.) — both are the only external dependencies used anywhere in the project.
Submit code + results to dropbox; graph to discussion topic; note team members if applicable ⚠️ Action needed This was a solo run (no team). Everything is staged locally under this HW3/ folder — you still need to upload it to your course's Dropbox/discussion topic yourself; nothing was submitted anywhere on your behalf, and no GitHub repository was created or touched anywhere in this process (per your instructions).

Bottom line: every technical requirement of the assignment is satisfied. The only remaining step is yours: actually submitting the folder's contents (and the PNG) to your course's dropbox and discussion topic by the due date.

2. AI-use disclosure (per your instructor's note that AI use is permitted if cited)

All code, benchmark harnesses, plots, and reports in this HW3/ folder were produced with the assistance of Claude (Anthropic), acting as an AI pair programmer per your explicit instructions (see ../instructions.txt) and per your instructor's stated policy allowing AI use as long as it's cited. You should carry a citation to this effect into your actual submission — e.g. a line in your write-up such as: "Code and analysis were developed with the assistance of Claude (Anthropic); the algorithm design (Randomized Quicksort) follows Cormen, Leiserson, Rivest & Stein, Introduction to Algorithms, Ch. 5."

3. Results

See all_results.csv for the combined machine-readable data (246 rows across 15 languages), and combined_plot.png / combined_plot_loglog.png / combined_plot_compiled_zoom.png for the graphs. Max n reached and time at that n per language, sorted fastest-at-max-n to slowest:

Language Max n reached Time at max n Iterations run
C++ 65,536,000 5.45 s 17
C 65,536,000 5.59 s 17
Zig 65,536,000 5.59 s 17
Assembly 65,536,000 5.95 s 17
Rust 65,536,000 5.88 s 17
F# 65,536,000 5.87 s 17
Go 65,536,000 6.71 s 17
C# 65,536,000 6.44 s 17
Java 65,536,000 7.81 s 17
Common Lisp 65,536,000 8.80 s 17
Pascal 65,536,000 9.29 s 17
PHP 8,192,000 8.24 s 14
Python 2,048,000 5.00 s 12
TypeScript 32,768,000 4.04 s 16
JavaScript 65,536,000 13.36 s 17

(TypeScript and JavaScript aren't directly comparable by "max n reached" the way the others are — both compile to/run as the same V8 JavaScript under Node, so their numbers track closely at every shared n; TypeScript's run happened to land just under the 4.0s cutoff at a smaller n and stopped one iteration earlier by chance, not because it's meaningfully different from plain JS. See §4 below.)

4. Discussion: does the curve match expected O(n log n)?

For a function that grows as Θ(n log n), doubling n should roughly double the runtime, with a small additional factor from the growing log term — the per-doubling ratio should sit a bit above 2.0 at small n and settle in toward ~2.0–2.3x as n grows large (since log₂(2n)/log₂(n) → 1 as n → ∞, the "extra" factor beyond a pure 2x shrinks slowly). That is almost exactly what every language's data shows once past the first few small-n iterations (which are dominated by timer resolution and one-time warmup costs, not the algorithm):

Taken together: every language's curve matches the expected O(n log n) asymptotic behavior of randomized quicksort (with JavaScript's one large-n anomaly noted above as a real, reported outlier rather than glossed over). The visible differences between languages are overwhelmingly constant-factor effects (compiled vs. interpreted, managed-runtime JIT/GC overhead, optimizer aggressiveness) rather than differences in algorithmic growth — exactly the distinction the assignment's prompt ("runtime is just one piece of the puzzle...") is pointing at. The full 15-language spread, fastest to slowest at n=65.5M (or each language's own max n), spans roughly 5.45s (C++) to 13.36s (JavaScript) among languages that reached large n, plus Python and TypeScript stopping at much smaller n under the same 4.0s budget — a single order of magnitude in per-operation cost separating a hand-optimized systems language from an interpreted dynamic one, which is a genuinely useful, concrete number for the "runtime is just one piece of the puzzle" discussion the assignment asks for.

5. Per-language detail

Full detail — exact compiler/runtime versions, RNG/pivot mechanics, external code citations, complete results tables, and language-specific anomaly notes — is in each language's own report:

6. What's in this folder

HW3/
  DESIGN.md                  shared experiment protocol every language followed
                              (includes a "Round 2 languages" section covering the 8 added later)
  c/, cpp/, csharp/, java/, python/, rust/, go/,
  javascript/, typescript/, fsharp/, zig/, lisp/, pascal/, asm/, php/
                              source code + README.md (build/run instructions) per language
  results/
    <lang>.csv                per-language raw (n, time_seconds) data
    all_results.csv           combined data, all 15 languages (246 rows)
    make_plot.py               script that builds the combined CSV + all plots
    combined_plot.png          REQUIRED deliverable: linear-axis line graph, all 15 languages
    combined_plot_loglog.png   log-log view (much more legible across this 15-language, huge-n-range spread)
    combined_plot_compiled_zoom.png
                                zoom on the 7 tightly-clustered native-compiled languages
  reports/
    <lang>_report.md          per-language report (version, RNG method, citation, results, analysis)
    FINAL_COMPARISON.md        this file

7. Languages requested but not included, and why

The student asked to expand the comparison further, including several genuinely obscure or non-existent languages. None of the following were implemented, for the reasons given — none were silently skipped without explanation:

Not real, or no working modern toolchain exists at all: R++ (not a recognized programming language), PEARL (a 1970s–80s German industrial real-time language with no maintained Linux toolchain), Opal (dead academic language, unmaintained since the late 1990s), Mercury, Lucid, and Euler (historical/research languages with no working modern compiler found), Cobra (.NET-hosted language, last released ~2012, effectively abandoned). OpenCL was also excluded — it's a GPU-kernel framework hosted from C/C++, not a standalone language, and doesn't fit a "single function, timed on CPU" model without a substantial rewrite. NASM was not treated as a separate language slot — it's the assembler used to implement the Assembly entry.

Real and common, but skipped for this round: R, Prolog, Erlang, Elixir, Swift, and COBOL. None had apt packages available in this environment (its package mirror was missing many otherwise-standard packages, including ones as common as nasm and nodejs), so each would have required a substantial from-source bootstrap. That tradeoff became harder to justify after this same WSL environment's Linux-side state proved unreliable during setup of the 8 languages that were added — an idle-timeout was silently discarding installed packages between commands (worked around by setting vmIdleTimeout=-1 in .wslconfig), and one installed tool's own script file was found corrupted after being written (worked around by calling its underlying binary directly — both documented in ../DESIGN.md's "Round 2 languages" section). Given that instability, six more from-source builds was a poor time/risk tradeoff for a 15-point homework assignment that already covers 15 languages here — but they're all real, well-documented languages and could be added in a future round if you want to push further.

No GitHub repository or git history was created or touched anywhere in this project, per your instructions — everything lives locally in this folder, ready for you to zip up / copy into your dropbox submission.