Chapter 3: Mathematical Foundations for DSA
3.01Beginner9 topics18 min4 interactive animations

Arithmetic essentials

The arithmetic that algorithm analysis leans on: integer division and remainder, floor and ceiling, absolute value, powers, roots, logarithms, exponent laws, factorials and scientific notation, with the Java forms that avoid rounding and overflow bugs.

Learning goals

  • Use division, remainder, floor and ceiling correctly for positive and negative numbers
  • Compute powers, roots and logarithms in integer arithmetic
  • Know how fast factorials and powers outgrow int and long

Prerequisites

Java language essentials
3.01.1

Integer division

For integers, a / b gives the quotient truncated toward zero and a % b the remainder, with a == (a / b) * b + a % b. Dividing by 10 removes the last digit and % 10 reads it, which is how you process digits.

Run the digit-sum animation: each step takes n % 10 and then n / 10.

Java
1int n = 4072, s = 0;
2while (n > 0) { s += n % 10; n /= 10; } // 2 + 7 + 0 + 4 = 13
3int q = 17 / 5, r = 17 % 5; // q = 3, r = 2: 17 = 3*5 + 2

Sum of digits

Interactive · edit the input

Your input

Try

Recursion tree · 1 call

sumDigits(4821)…
Running now
Call

Call sumDigits(4821).

Step 1 / 20
Java
1static int sumDigits(int n) {
2 if (n == 0) return 0; // no digits left
3 return n % 10 + sumDigits(n / 10); // last digit + the rest
4}

Live state

1 calls

n

4821

No condition evaluated on this step

Call stack (top first)

  1. sumDigits(4821)
Execution trace (dry run table)Show 20 steps
StepLineStateWhat happens
1L1n=4821Call sumDigits(4821).
2L2n=4821Split 4821 into last digit 1 and the rest 482.
3L3n=4821 digit=1Call sumDigits(482) for the remaining digits.
4L1n=482Call sumDigits(482).
5L2n=482Split 482 into last digit 2 and the rest 48.
6L3n=482 digit=2Call sumDigits(48) for the remaining digits.
7L1n=48Call sumDigits(48).
8L2n=48Split 48 into last digit 8 and the rest 4.
9L3n=48 digit=8Call sumDigits(4) for the remaining digits.
10L1n=4Call sumDigits(4).
11L2n=4Split 4 into last digit 4 and the rest 0.
12L3n=4 digit=4Call sumDigits(0) for the remaining digits.
13L1n=0Call sumDigits(0).
14L2n=0Base case: no digits left.
15L2n=0 return=0return 0.
16L3n=4 return=44 + 0 = 4.
17L3n=48 return=128 + 4 = 12.
18L3n=482 return=142 + 12 = 14.
19L3n=4821 return=151 + 14 = 15.
20L3return=15The digits of 4821 sum to 15. Calls = number of digits + 1 = 5.
3.01.2

Remainder

The remainder (modulo) tells how far a number is past the last multiple of the divisor. It is used for parity (n % 2), cyclic indexes ((i + 1) % n), hashing and number theory. In Java the sign follows the dividend, so use Math.floorMod when a non-negative result is required.

Euclid's algorithm uses the identity gcd(a, b) = gcd(b, a mod b). Step through it below.

Java
1int even = 10 % 2; // 0
2int next = (4 + 1) % 5; // 0: wraps around a 5-element ring
3int prev = Math.floorMod(0 - 1, 5); // 4
4int g = gcd(48, 18); // 6
5static int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }

Greatest common divisor (Euclid)

Interactive · edit the input

Your input

Try

Recursion tree · 1 call

gcd(252, 105)…
Running now
Call

Call gcd(252, 105).

Step 1 / 16
Java
1static int gcd(int a, int b) {
2 if (b == 0) return a; // base case
3 return gcd(b, a % b); // same answer, smaller numbers
4}

Live state

1 calls

a

252

b

105

No condition evaluated on this step

Call stack (top first)

  1. gcd(252, 105)
Execution trace (dry run table)Show 16 steps
StepLineStateWhat happens
1L1a=252 b=105Call gcd(252, 105).
2L2a=252 b=105b is not 0. 252 % 105 = 42, and gcd(a, b) = gcd(b, a % b).
3L3a=252 b=105 a % b=42Call gcd(105, 42).
4L1a=105 b=42Call gcd(105, 42).
5L2a=105 b=42b is not 0. 105 % 42 = 21, and gcd(a, b) = gcd(b, a % b).
6L3a=105 b=42 a % b=21Call gcd(42, 21).
7L1a=42 b=21Call gcd(42, 21).
8L2a=42 b=21b is not 0. 42 % 21 = 0, and gcd(a, b) = gcd(b, a % b).
9L3a=42 b=21 a % b=0Call gcd(21, 0).
10L1a=21 b=0Call gcd(21, 0).
11L2a=21 b=0b is 0, so 21 divides everything left: the answer is 21.
12L2a=21 b=0 return=21return 21. Nothing more to do on the way back: this is a tail call.
13L3a=42 b=21 return=21return 21. Nothing more to do on the way back: this is a tail call.
14L3a=105 b=42 return=21return 21. Nothing more to do on the way back: this is a tail call.
15L3a=252 b=105 return=21return 21. Nothing more to do on the way back: this is a tail call.
16L3return=21gcd(252, 105) = 21 after 4 calls.
3.01.3

Floor and ceiling

⌊x⌋ is the greatest integer ≤ x and ⌈x⌉ is the smallest integer ≥ x. For positive integers, ⌈a / b⌉ = (a + b - 1) / b, which avoids floating point. For negative numbers Java division truncates, so use Math.floorDiv for floors.

Binary search takes ⌊log₂ n⌋ + 1 probes at most, and merge sort recursion depth is ⌈log₂ n⌉.

Java
1int pages = (10 + 3 - 1) / 3; // ceil(10 / 3) = 4
2int f = Math.floorDiv(-7, 2); // -4
3int c = -Math.floorDiv(-(-7), 2); // ceil(-7 / 2) = -3
4double d = Math.ceil(10 / 3.0); // 4.0
3.01.4

Absolute value

|x| is the distance from zero. In code it measures differences regardless of direction: Math.abs(a - b). The triangle inequality |a + b| ≤ |a| + |b| appears in Manhattan distance and in proofs.

Beware: Math.abs(Integer.MIN_VALUE) is negative, and Math.abs(a - b) can overflow for large operands. Compare with Integer.compare when you only need order.

Java
1int manhattan = Math.abs(1 - 4) + Math.abs(2 - (-2)); // 3 + 4 = 7
2long safeDiff = Math.abs((long) a - b); // widen before subtracting
3.01.5

Powers and roots

xⁿ is x multiplied n times; the n-th root undoes it. Integer powers grow quickly: 2³¹ already exceeds int. Compute powers with a loop or binary exponentiation (about log₂ n multiplications) rather than Math.pow, which returns an inexact double.

Watch fast exponentiation square the base and halve the exponent.

Java
1static long pow(long base, int exp, long mod) {
2 long result = 1; base %= mod;
3 while (exp > 0) {
4 if ((exp & 1) == 1) result = result * base % mod;
5 base = base * base % mod;
6 exp >>= 1;
7 }
8 return result;
9}
10static long isqrt(long n) { // floor(sqrt(n)), safe up to Long.MAX_VALUE
11 if (n < 2) return n;
12 long r = (long) Math.sqrt((double) n);
13 while (r > n / r) r--; // r * r > n, written without multiplying
14 while (r + 1 <= n / (r + 1)) r++; // (r + 1)^2 <= n
15 return r;
16}

Power function: halving the exponent

Interactive · edit the input

Your input

Try

Recursion tree · 1 call

power(2, 13)…
Running now
Call

Call power(2, 13).

Step 1 / 20
Java
1static long power(long x, int n) {
2 if (n == 0) return 1; // x^0 = 1
3 long half = power(x, n / 2); // solve a problem half the size
4 return (n % 2 == 0) ? half * half : half * half * x;
5}

Live state

1 calls0 multiplications

x

2

n

13

No condition evaluated on this step

Call stack (top first)

  1. power(2, 13)
Execution trace (dry run table)Show 20 steps
StepLineStateWhat happens
1L1x=2 n=13Call power(2, 13).
2L2n=13n = 13 is not 0. Halve it: 13 / 2 = 6.
3L3x=2 n=13Compute power(2, 6) once and reuse it.
4L1x=2 n=6Call power(2, 6).
5L2n=6n = 6 is not 0. Halve it: 6 / 2 = 3.
6L3x=2 n=6Compute power(2, 3) once and reuse it.
7L1x=2 n=3Call power(2, 3).
8L2n=3n = 3 is not 0. Halve it: 3 / 2 = 1.
9L3x=2 n=3Compute power(2, 1) once and reuse it.
10L1x=2 n=1Call power(2, 1).
11L2n=1n = 1 is not 0. Halve it: 1 / 2 = 0.
12L3x=2 n=1Compute power(2, 0) once and reuse it.
13L1x=2 n=0Call power(2, 0).
14L2n=0Base case: any number to the power 0 is 1.
15L2n=0 return=1return 1.
16L4n=1 half=1 return=2n is odd: half × half × x = 1 × 1 × 2 = 2.
17L4n=3 half=2 return=8n is odd: half × half × x = 2 × 2 × 2 = 8.
18L4n=6 half=8 return=64n is even: half × half = 8 × 8 = 64.
19L4n=13 half=64 return=8192n is odd: half × half × x = 64 × 64 × 2 = 8192.
20L4return=81922^13 = 8192 with 5 calls (about log₂ n) instead of 13 multiplications.
3.01.6

Logarithms

log_b(n) is the exponent to which b must be raised to get n: log₂ 1024 = 10. Equivalently it counts how many times you can halve n before reaching 1. That is why binary search, balanced trees and heaps take O(log n).

Change the starting value in the animation and watch the number of halvings equal ⌊log₂ n⌋.

nlog₂ n
83
1,02410
1,048,576 (2²⁰)20
1,000,000,000about 29.9
Java
1int n = 1000, steps = 0;
2while (n > 1) { n /= 2; steps++; } // steps = 9 = floor(log2(1000))
3int floorLog2 = 31 - Integer.numberOfLeadingZeros(1000); // 9
4double ln = Math.log(1000) / Math.log(2); // 9.9657...

Logarithm = how many times can n be halved?

Interactive · edit the input

Your input

Try

value of n after each step

100start
50÷2 (#1)
25÷2 (#2)
12÷2 (#3)
6÷2 (#4)
3÷2 (#5)
1÷2 (#6)
Setup

log₂ 100 answers “to what power must 2 be raised to reach 100?”. Equivalently: how many halvings take 100 down to 1?

Step 1 / 14
Java
1static int halvings(int n) { // = floor(log2 n) for n >= 1
2 int count = 0;
3 while (n > 1) {
4 n /= 2; // integer division
5 count++;
6 }
7 return count;
8}
9
10static int doublings(int n) { // = ceil(log2 n)
11 int count = 0;
12 for (long x = 1; x < n; x *= 2) count++;
13 return count;
14}

Live state

n

100

count

0

No condition evaluated on this step
Execution trace (dry run table)Show 14 steps
StepLineStateWhat happens
1L2n=100 count=0log₂ 100 answers “to what power must 2 be raised to reach 100?”. Equivalently: how many halvings take 100 down to 1?
2L3n=100 count=0100 > 1, so halve again.
3L5n=50 count=1n = 50 after 1 halving.
4L3n=50 count=150 > 1, so halve again.
5L5n=25 count=2n = 25 after 2 halvings.
6L3n=25 count=225 > 1, so halve again.
7L5n=12 count=3n = 12 after 3 halvings.
8L3n=12 count=312 > 1, so halve again.
9L5n=6 count=4n = 6 after 4 halvings.
10L3n=6 count=46 > 1, so halve again.
11L5n=3 count=5n = 3 after 5 halvings.
12L3n=3 count=53 > 1, so halve again.
13L5n=1 count=6n = 1 after 6 halvings.
14L7return=6 log2(n)=6.644return 6 = ⌊log₂ 100⌋ (log₂ 100 ≈ 6.644). Even for n = 1,000,000 this is only 19 steps, which is why O(log n) algorithms feel instant.
3.01.7

Exponents

Laws: xᵃ · xᵇ = xᵃ⁺ᵇ, (xᵃ)ᵇ = xᵃᵇ, x⁻ᵃ = 1/xᵃ, x⁰ = 1. Exponentials grow faster than any polynomial, and logarithms grow slower than any positive power. Hence 2ⁿ ≫ n² ≫ n log n ≫ n ≫ log n for large n.

Useful anchors: 2¹⁰ = 1,024 ≈ 10³, so 2²⁰ ≈ 10⁶ and 2³⁰ ≈ 10⁹.

ExpressionValue
2¹⁰1,024
2²⁰1,048,576
2³¹ - 12,147,483,647 (int max)
2⁶³ - 19,223,372,036,854,775,807 (long max)
10⁹ + 71,000,000,007 (common modulus)
3.01.8

Factorials

n! = n · (n-1) · … · 1, with 0! = 1. It counts the orderings of n distinct items and grows faster than any exponential: 12! = 479,001,600 is the largest factorial in int, and 20! = 2,432,902,008,176,640,000 is the largest in long. 21! overflows long.

Algorithms that try all orderings are practical only up to about n = 10 or 11.

Java
1long f = 1;
2for (int i = 2; i <= 20; i++) f *= i; // 2432902008176640000
3// i = 21 would overflow: use BigInteger beyond 20!
4BigInteger big = BigInteger.ONE;
5for (int i = 2; i <= 30; i++) big = big.multiply(BigInteger.valueOf(i));
3.01.9

Scientific notation

Scientific notation writes a value as m × 10ᵉ. It makes constraints and growth easy to compare: n ≤ 2 × 10⁵ means 200,000. Java accepts 1e9 (a double) and 1_000_000_000 (an int).

(int) 1e9 is 1,000,000,000, but 1e18 does not fit in int and needs (long) 1e18 or the literal 1_000_000_000_000_000_000L.

NotationValueFits in
1e5100,000int
1e91,000,000,000int
2e92,000,000,000int (just)
3e93,000,000,000long
1e1810¹⁸long
1e1910¹⁹BigInteger

Practice ladder

Now try it yourself

Easy

  • Compute ⌈17 / 5⌉ with integers only
  • Count the halvings needed to reduce 100 to 1

Medium

  • Write isqrt(long) without floating point errors
  • Compute 3²⁰⁰ mod 1,000,000,007 with fast exponentiation

Advanced

  • Find the smallest n for which n! exceeds 10¹⁸ and explain how to detect the overflow

Key takeaways

  • Use (a + b - 1) / b for ceiling division and floorMod/floorDiv for negatives.
  • log₂ n is the number of halvings; it explains every O(log n).
  • 20! is the last factorial in long; 2³¹ - 1 and 2⁶³ - 1 are the integer limits.