Cross-Language Energy Comparison
The same algorithm, implemented in six languages, analyzed by Joule. This comparison reveals the energy cost of language abstractions and runtime overhead.
The Algorithm
Iterative Fibonacci computing fib(30). Chosen because it's simple enough to implement identically in every language, with enough arithmetic to produce meaningful energy differences.
Python
def fibonacci(n):
if n <= 1:
return n
a = 0
b = 1
for i in range(2, n + 1):
temp = a + b
a = b
b = temp
return b
def main():
result = fibonacci(30)
print(result)
main()
JavaScript
function fibonacci(n) {
if (n <= 1) return n;
let a = 0;
let b = 1;
for (let i = 2; i <= n; i++) {
const temp = a + b;
a = b;
b = temp;
}
return b;
}
function main() {
const result = fibonacci(30);
console.log(result);
}
main();
TypeScript
function fibonacci(n: number): number {
if (n <= 1) return n;
let a: number = 0;
let b: number = 1;
for (let i: number = 2; i <= n; i++) {
const temp: number = a + b;
a = b;
b = temp;
}
return b;
}
function main(): void {
const result: number = fibonacci(30);
console.log(result);
}
main();
C
#include <stdio.h>
int fibonacci(int n) {
if (n <= 1) return n;
int a = 0;
int b = 1;
for (int i = 2; i <= n; i++) {
int temp = a + b;
a = b;
b = temp;
}
return b;
}
int main() {
int result = fibonacci(30);
printf("%d\n", result);
return 0;
}
Go
package main
import "fmt"
func fibonacci(n int) int {
if n <= 1 {
return n
}
a := 0
b := 1
for i := 2; i <= n; i++ {
temp := a + b
a = b
b = temp
}
return b
}
func main() {
result := fibonacci(30)
fmt.Println(result)
}
Rust
fn fibonacci(n: i32) -> i32 { if n <= 1 { return n; } let mut a = 0; let mut b = 1; for _i in 2..=n { let temp = a + b; a = b; b = temp; } b } fn main() { let result = fibonacci(30); println!("{}", result); }
Running the Comparison
joulec --lift python fibonacci.py
joulec --lift js fibonacci.js
joulec --lift ts fibonacci.ts
joulec --lift c fibonacci.c
joulec --lift go fibonacci.go
joulec --lift rust fibonacci.rs
Results
| Language | fibonacci() Energy | main() Energy | Total | Confidence |
|---|---|---|---|---|
| C | 1.75 nJ | 0.85 nJ | 2.60 nJ | 0.90 |
| Rust | 1.75 nJ | 1.10 nJ | 2.85 nJ | 0.90 |
| Go | 1.95 nJ | 1.20 nJ | 3.15 nJ | 0.85 |
| JavaScript | 2.80 nJ | 1.50 nJ | 4.30 nJ | 0.85 |
| TypeScript | 2.80 nJ | 1.50 nJ | 4.30 nJ | 0.85 |
| Python | 3.40 nJ | 1.80 nJ | 5.20 nJ | 0.80 |
All programs produce the correct result: 832040.
Analysis
Why C and Rust Are Cheapest
Both C and Rust map directly to integer arithmetic with no runtime overhead. The fibonacci() function compiles to:
- 29 integer additions (0.05 pJ each = 1.45 pJ)
- 58 register moves (~0 pJ, register-to-register)
- 29 loop iterations with branch (0.1 pJ each = 2.9 pJ)
- 1 comparison + branch for the
n <= 1check
Total compute: ~4.4 pJ. The remaining energy comes from function call overhead, stack frame setup, and memory loads.
Rust's slightly higher main() cost accounts for println! macro expansion, which involves formatting machinery that printf avoids.
Why Go Costs Slightly More
Go's runtime includes goroutine scheduling infrastructure even for single-threaded programs. The fmt.Println call also involves reflection-based formatting that adds overhead beyond C's printf.
Why JavaScript Costs More
JavaScript numbers are f64 (double-precision float) even for integer arithmetic. The fibonacci() loop performs float addition instead of integer addition:
- Integer add: 0.05 pJ
- Float add: 0.35 pJ (7x more expensive)
This single type system decision accounts for most of JavaScript's energy premium.
Why TypeScript Equals JavaScript
TypeScript type annotations (n: number, let a: number) are erased before analysis. The runtime behavior is identical to JavaScript — same f64 arithmetic, same energy profile.
Why Python Costs the Most
Python's dynamic dispatch adds overhead per operation. Each + involves:
- Type check on both operands
- Method lookup (
__add__) - Result allocation (for large integers)
The energy model accounts for this dispatch overhead, making Python ~2x more expensive than C for pure arithmetic.
Thermal State Impact
Running with different thermal states changes the cost model's power efficiency factor:
joulec --lift c fibonacci.c --thermal-state cool # aggressive optimization
joulec --lift c fibonacci.c --thermal-state hot # conservative, reduced SIMD
| Thermal State | C Energy | Python Energy | Ratio |
|---|---|---|---|
| cool (< 50C) | 2.40 nJ | 4.80 nJ | 2.0x |
| nominal (50-70C) | 2.60 nJ | 5.20 nJ | 2.0x |
| hot (85-95C) | 3.10 nJ | 6.20 nJ | 2.0x |
The absolute energy increases with temperature (thermal resistance reduces efficiency), but the ratio between languages stays constant for this workload because the algorithm is compute-bound with no SIMD opportunities.
The Energy Cost of Abstraction
This comparison quantifies something developers intuit but rarely measure: higher-level languages consume more energy for the same computation. The gap is not enormous — Python costs 2x what C costs for pure arithmetic — but it compounds across millions of function calls in production systems.
Joule makes this cost visible. Whether you're choosing a language for a new project, optimizing a hot path, or justifying a rewrite, you now have picojoule-level data to inform the decision.