ℹ️ Select 'Choose Exercise', or randomize 'Next Random Exercise' in selected language.

Choose Exercise:
Timer 00:00
WPM --
Score --
Acc --
Correct chars --

Solidity: Calculate Factorial with Recursion

Solidity

Goal -- WPM

Ready
Exercise Algorithm Area
1pragma solidity ^0.8.0;
2
3contract MathUtils {
4
5/**
6* @dev Calculates the factorial of a non-negative integer using recursion.
7* @param n The non-negative integer for which to calculate the factorial.
8* @return The factorial of n.
9* @notice Reverts if n is negative or if the result overflows uint256.
10*/
11function factorialRecursive(uint256 n) internal pure returns (uint256 result) {
12// Base case: factorial of 0 is 1.
13if (n == 0) {
14return 1;
15}
16
17// Check for potential overflow before multiplication.
18// If n > MAX_UINT256 / factorialRecursive(n - 1), then n * factorialRecursive(n - 1) would overflow.
19// This check is crucial for preventing unexpected behavior with large inputs.
20uint256 prevFactorial = factorialRecursive(n - 1);
21if (n > type(uint256).max / prevFactorial) {
22revert("MathUtils: factorial overflow");
23}
24
25// Recursive step: n! = n * (n-1)!
26result = n * prevFactorial;
27return result;
28}
29
30/**
31* @dev Calculates the factorial of a non-negative integer using iteration.
32* @param n The non-negative integer for which to calculate the factorial.
33* @return The factorial of n.
34* @notice Reverts if n is negative or if the result overflows uint256.
35*/
36function factorialIterative(uint256 n) internal pure returns (uint256 result) {
37// Handle the base case: factorial of 0 is 1.
38result = 1;
39
40// Iterate from 1 up to n, multiplying result by each number.
41// The loop invariant is that 'result' holds the factorial of the current loop counter.
42for (uint256 i = 1; i <= n; i++) {
43// Check for potential overflow before multiplication.
44if (i > type(uint256).max / result) {
45revert("MathUtils: factorial overflow");
46}
47result = result * i;
48}
49return result;
50}
51
52/**
53* @dev Calculates the nth Fibonacci number using recursion.
54* @param n The index of the Fibonacci number to calculate.
55* @return The nth Fibonacci number.
56* @notice This implementation is inefficient due to repeated calculations.
57*/
58function fibonacciRecursive(uint256 n) internal pure returns (uint256) {
59if (n == 0) {
60return 0;
61} else if (n == 1) {
62return 1;
63} else {
64return fibonacciRecursive(n - 1) + fibonacciRecursive(n - 2);
65}
66}
67}
Algorithm description viewbox

Solidity: Calculate Factorial with Recursion

Algorithm description:

This Solidity contract `MathUtils` provides a `factorialRecursive` function to compute the factorial of a non-negative integer using recursion. The factorial of a non-negative integer `n`, denoted by `n!`, is the product of all positive integers less than or equal to `n`. This function is essential in combinatorial mathematics and probability theory. For instance, it's used to calculate the number of ways to arrange `n` distinct items, which is `n!`, or in the calculation of binomial coefficients.

Algorithm explanation:

The `factorialRecursive` function calculates `n!` by first checking the base case: if `n` is 0, it returns 1. Otherwise, it recursively calls itself with `n-1` to get `(n-1)!`. Before performing the multiplication `n * (n-1)!`, it checks for potential `uint256` overflow. If `n` is greater than `type(uint256).max / (n-1)!`, it reverts. The time complexity of this recursive implementation is O(n) because each call to `factorialRecursive` makes one recursive call, leading to `n` calls. However, due to the overhead of function calls and the repeated calculation of subproblems (e.g., `factorialRecursive(3)` is calculated multiple times when computing `factorialRecursive(5)`), it's less efficient than an iterative approach. The space complexity is O(n) due to the call stack depth. The invariant is that `factorialRecursive(k)` correctly computes `k!` for all `k < n` when `factorialRecursive(n)` is called.

Pseudocode:

function factorialRecursive(n):
  if n is 0:
    return 1
  else:
    prevFactorial = factorialRecursive(n - 1)
    if n > MAX_UINT256 / prevFactorial:
      revert "Overflow"
    return n * prevFactorial