← Math in Practice
Concept Quantities and representation

Ratios, rates, and proportions

Keep the units and denominator attached to the number.

A capacity alert says “traffic is up 20%,” while a dashboard says the service handles 900 requests per second. Before adding machines, work out what changed, over which window, and how that rate compares with capacity.

The judgment to keep

Every rate has a numerator, a denominator, and units. Keep those attached while comparing workloads, capacity, and change.

TypeScriptGo Request throughput · utilization · percentage change
01 / Start with the alert

“Twenty percent higher” is not yet a capacity diagnosis.

The on-call dashboard compares 54,000 requests over the last minute with a previous hour’s chart. Another panel shows a steady 900 requests per second. A teammate calls the change “20%.” These observations may use different windows or denominators, so the percentage is not ready to guide a scaling decision.

Write down the count, the elapsed time, the service boundary being counted, and the capacity estimate. If the window changes, compare equivalent windows before inferring growth.

Case file / Capacity alertRequests arrive faster than the team expected.
Observed count
54,000 completed requests in 60 seconds.
Estimated capacity
1,200 requests per second under this workload.
Question
What rate did the service see, and how much of that estimated capacity did it use?
Invariant
Compare the same request class and time window; do not turn a count into a rate without its duration.
Leave with: the count, time window, request boundary, and capacity estimate that make the comparison meaningful.
02 / Name the quantities

A rate is a ratio with units that tell you what it means.

A ratio compares two quantities. A rate compares quantities with different dimensions, often work over time: requests / seconds, bytes / second, or errors / requests. Units are part of the answer. 900 requests/minute and 900 requests/second differ by a factor of 60.

For throughput, divide the number of completed operations by elapsed time: 54,000 requests ÷ 60 seconds = 900 requests/second. Keep the count tied to the interval in which those completions were observed. A short burst and a minute-wide average can have the same count only if their windows also match.

Proportion describes a part relative to a whole. Utilization is the observed work rate divided by the capacity rate: 900 requests/s ÷ 1,200 requests/s = 0.75. The units cancel because both rates measure the same kind of work per second; express 0.75 as 75%.

Same request boundary · same 60-second window
QuantityCalculationResultUse
Throughput54,000 requests ÷ 60 s900 requests/sObserved completed work per unit time
Capacity rateGiven estimate1,200 requests/sMaximum sustainable rate for this workload
Utilization900 ÷ 1,2000.75 = 75%Observed rate as a fraction of estimated capacity
Checkpoint: say the units aloud. If the numerator and denominator do not describe the same work and interval, pause before comparing.
03 / Compare like with like

Percent change and percentage-point change answer different questions.

Suppose a cache hit rate moves from 90% to 95%. The change is 5 percentage points. Relative to the original 90%, it is a (95 − 90) ÷ 90 ≈ 5.56% increase. Both calculations are valid, but they have different denominators. Name the one you mean.

Likewise, a 20% increase in demand does not mean utilization rises by 20 percentage points. If a service starts at 75% utilization and demand rises by 20% while capacity stays fixed, the new utilization is 75% × 1.20 = 90%—a 15 percentage-point increase. That estimate assumes the same request mix and capacity.

Leave with: the baseline and the denominator behind every percentage change.
04 / Change the inputs

Change one quantity and see which rate moves.

Throughput labCount → rate → capacity share

Change the measured count or window. Keep the capacity estimate for the same request type.

Observed rate900.0 requests/s54000 requests ÷ 60 s
Capacity share75.0%900.0 ÷ 1200 requests/s

This calculator assumes the count and capacity cover the same request class and interval. It does not estimate tail latency or prove a safe operating limit.

Try doubling the count while holding the window and capacity fixed. The rate and utilization should double. Then double both count and window: the total work changes, but the rate should return to its starting value. That is why counts without durations can mislead.

Experiment: choose values that produce 100% utilization. What new evidence would you want before calling that the system’s safe limit?
05 / Practice in code

Make invalid denominators visible.

The calculation is simple; the inputs determine whether it means anything. Reject a zero or negative duration and non-positive capacity. The returned utilization is a fraction; multiply by 100 only for a percent display. Keep validation and units explicit at the boundary.

Compare the same calculation in TypeScript and Go.

Both versions preserve the rate units and reject invalid denominators.

TypeScriptThroughput and utilization · units retained
throughput.ts
export function requestsPerSecond(requests: number, elapsedSeconds: number): number {
	if (!Number.isFinite(requests) || requests < 0 || !Number.isInteger(requests)) {
		throw new Error('requests must be a non-negative integer');
	}
	if (!Number.isFinite(elapsedSeconds) || elapsedSeconds <= 0) {
		throw new Error('elapsedSeconds must be positive');
	}
	return requests / elapsedSeconds;
}

export function utilization(ratePerSecond: number, capacityPerSecond: number): number {
	if (!Number.isFinite(ratePerSecond) || ratePerSecond < 0)
		throw new Error('rate must be non-negative');
	if (!Number.isFinite(capacityPerSecond) || capacityPerSecond <= 0) {
		throw new Error('capacity must be positive');
	}
	return ratePerSecond / capacityPerSecond;
}
GoThroughput and utilization · units retained
throughput.go
package mathpractice

import (
	"errors"
	"math"
)

func RequestsPerSecond(requests, elapsedSeconds float64) (float64, error) {
	if math.IsNaN(requests) || math.IsInf(requests, 0) || requests < 0 || math.Trunc(requests) != requests {
		return 0, errors.New("requests must be a non-negative integer")
	}
	if math.IsNaN(elapsedSeconds) || math.IsInf(elapsedSeconds, 0) || elapsedSeconds <= 0 {
		return 0, errors.New("elapsedSeconds must be positive")
	}
	return requests / elapsedSeconds, nil
}

func Utilization(ratePerSecond, capacityPerSecond float64) (float64, error) {
	if math.IsNaN(ratePerSecond) || math.IsInf(ratePerSecond, 0) || ratePerSecond < 0 {
		return 0, errors.New("rate must be non-negative")
	}
	if math.IsNaN(capacityPerSecond) || math.IsInf(capacityPerSecond, 0) || capacityPerSecond <= 0 {
		return 0, errors.New("capacity must be positive")
	}
	return ratePerSecond / capacityPerSecond, nil
}
06 / Make the next call

Use the ratio to ask a better operational question.

Keep this distinction: the arithmetic can be exact while the inputs are estimates. A result such as 75% is only as trustworthy as the request count, duration, and capacity measurement behind it.

Question to keep: what is counted, over what duration, at which system boundary, and against what capacity estimate?