Skip to content

Commit 40757fe

Browse files
Optimize Fibonacci.fibonacci
Runtime improvement (primary): The optimized version cuts execution time from ~169 ms to ~84.2 µs — a ~200k% speedup — by replacing the exponential recursive routine with an O(log n) iterative algorithm. What changed (specific optimizations) - Replaced naive recursion: removed fibonacci(n-1)+fibonacci(n-2) which performs an exponential number of function calls and repeated work. - Implemented the fast-doubling method iteratively: processes the bits of n (highest to lowest) and computes F(2k) and F(2k+1) via closed-form recurrences in a tight loop. - Eliminated recursion and allocations: uses two long locals (a, b) and simple arithmetic and bit operations (<<, >>, &), with no extra objects or call-stack growth. - Minimizes loop iterations by computing the highest set bit once (Integer.numberOfLeadingZeros) and looping only ~log2(n) times. Why this yields the big speedup - Algorithmic complexity: original is exponential in n (lots of redundant subcalls); fast-doubling runs in O(log n) arithmetic steps. For moderate/large n (tests use up to n=30 and beyond), that change dominates runtime. - Removes call overhead and duplicate computation: the profiler shows the original version incurred tens of millions of line hits (huge call/return traffic). The optimized version does only a small constant number of operations per bit of n, so total operations collapse dramatically. - CPU-friendly operations: arithmetic and bitwise operations are fast and branch-predictable; the loop body has a small fixed amount of work and straightforward branches, which modern JITs optimize well. Behavioral/compatibility notes (key impacts) - Correctness preserved for inputs in the same long-typed semantics: negative input still throws; base cases n <= 1 return immediately. - Stack-safety: recursion is gone — no risk of deep recursion or stack overflow for large n. - Overflow semantics unchanged: the function still returns long and will overflow in the same way as the original recursive version for very large n (no change in numeric range handling). - No new dependencies or allocations introduced; the function remains self-contained and lightweight. Where this matters (workloads/tests) - Hot paths and repeated calls: any code that repeatedly computes Fibonacci numbers (e.g., per-request, inside loops, or batch processing) will see large throughput and latency wins because per-call cost is tiny. - Larger n and performance-guarded tests: annotated tests (e.g., n=30, performance/timeouts) show the biggest wins — the optimized version runs orders of magnitude faster and easily satisfies timeouts. - Small n still fast: base cases are checked early, so there’s no regression for tiny inputs; tests for n=0..10 show microsecond or sub-microsecond times. Trade-offs and cautions - No regression in runtime; this change was accepted specifically for runtime improvement. - Keep the same numeric type expectations: if callers relied on detecting overflow by observing negative/wrapped long results, behavior remains the same so tests remain valid. - The implementation uses int bit operations to iterate bits of n; since n is an int, the loop bounds are correct and base cases handle n==0/1. Line-profiler evidence - Original profiler: huge total time and tens of millions of line hits caused by recursion. - Optimized profiler: total time collapsed to microseconds and line hits are small and concentrated in the iterative loop lines, matching the expected O(log n) behavior. Bottom line: this replaces an exponential-time recursive implementation with an iterative fast-doubling algorithm, producing the dramatic runtime improvement shown by the profiler and tests while preserving semantics and removing recursion-related risks.
1 parent 04b0dbd commit 40757fe

1 file changed

Lines changed: 21 additions & 1 deletion

File tree

code_to_optimize/java/src/main/java/com/example/Fibonacci.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,27 @@ public static long fibonacci(int n) {
2121
if (n <= 1) {
2222
return n;
2323
}
24-
return fibonacci(n - 1) + fibonacci(n - 2);
24+
// Iterative fast-doubling method (O(log n) time, O(1) space).
25+
long a = 0; // F(0)
26+
long b = 1; // F(1)
27+
// Process bits of n from highest to lowest
28+
int highestBit = 31 - Integer.numberOfLeadingZeros(n);
29+
for (int i = highestBit; i >= 0; --i) {
30+
// Compute:
31+
// c = F(2k) = F(k) * (2*F(k+1) - F(k))
32+
// d = F(2k+1) = F(k)^2 + F(k+1)^2
33+
long twoBminusA = (b << 1) - a;
34+
long c = a * twoBminusA;
35+
long d = a * a + b * b;
36+
if (((n >> i) & 1) == 0) {
37+
a = c;
38+
b = d;
39+
} else {
40+
a = d;
41+
b = c + d;
42+
}
43+
}
44+
return a;
2545
}
2646

2747
/**

0 commit comments

Comments
 (0)