5.4.2 · D4Scientific Computing (Python)

Exercises — Array creation — np.zeros, np.ones, np.linspace, np.arange, np.random

2,449 words11 min readBack to topic

Below is our reference figure. On a dark chalkboard it draws two rulers stacked vertically. The top ruler (yellow dots) is np.linspace(0, 1, 5): five glowing fenceposts at 0, 0.25, 0.5, 0.75, 1, with four blue "gap" braces between them — showing that 5 points make only 4 gaps. The bottom ruler (pink dots) is np.arange(0, 1, 0.25): marks at 0, 0.25, 0.5, 0.75, with a dashed white stop wall at 1.0 carrying a white "×" to signal that the stop is excluded. Keep this picture in mind — throughout the page "the top ruler" means linspace's included-endpoint behaviour and "the bottom ruler" means arange's excluded-stop behaviour.

Figure — Array creation — np.zeros, np.ones, np.linspace, np.arange, np.random

The symbol is the ceiling: round up to the next whole number (e.g. , ). We need "round up" because arange keeps taking whole steps and stops the moment the next step would reach or cross stop; it never emits a value at or beyond stop. The ceiling simply counts how many full steps fit strictly inside the interval.


Level 1 — Recognition

Can you read a call and predict its output shape, dtype, and contents?

L1.1

What does np.zeros((2, 3)) return? Give shape, dtype, and the array.

Recall Solution L1.1

WHAT: shape is passed as one tuple (2, 3) → 2 rows, 3 columns. WHY float: the default dtype of np.zeros is float64, so the entries print with a dot (0.). Shape (2, 3), dtype float64, six zeros.

L1.2

What is the dtype and the array for np.ones(4, dtype=int)?

Recall Solution L1.2

A bare 4 (not a tuple) means a 1-D array of length 4. We overrode the default float with dtype=int. Result: array([1, 1, 1, 1]). The dtype is the platform's default integer — typically int64 on 64-bit Linux/macOS, but int32 on some systems (e.g. Windows). The reliable takeaway: it is an integer dtype (note no dots), not the concrete bit-width.

L1.3

Predict the exact output of np.arange(3).

Recall Solution L1.3

One argument means start=0, step=1, stop=3 (exclusive). array([0, 1, 2]) — an integer dtype (arange keeps integer dtype when all args are ints; the exact width is platform-dependent). The value 3 is not included.


Level 2 — Application

Plug into the two formulas and produce the actual numbers.

L2.1

Compute the step and list every element of np.linspace(0, 1, 5).

Recall Solution L2.1

WHY num−1: 5 points create 4 gaps (fenceposts vs gaps — see the top ruler in the figure). Elements for : [0. , 0.25, 0.5 , 0.75, 1. ]. The stop 1.0 is included (endpoint=True).

L2.2

How many elements does np.arange(2, 20, 3) produce, and what is the last one?

Recall Solution L2.2

Elements: 2, 5, 8, 11, 14, 17. The last is 17; the next would be 20 which equals stop and is excluded.

L2.3

Give the step of np.linspace(0, 10, 10). (Students expect step 1 — check!)

Recall Solution L2.3

Not 1. To get step exactly 1 with endpoint 10, you need 11 points: np.linspace(0, 10, 11).


Level 3 — Analysis

Reason about edge cases, floats, and why a call behaves oddly.

L3.1

np.arange(0, 1, 0.1) — is its length 10 or 11? Explain in terms of floating point.

Recall Solution L3.1

By the formula, , if arithmetic were exact. WHY it wobbles: 0.1 cannot be stored exactly in binary (Floating-point representation and rounding errors). The stored value is slightly less than 0.1, so 10 accumulated steps land at roughly 0.9999999… — just under 1. Since that is < stop, one more value squeezes in, and you can get length 11 with a final entry near 0.9999999999999999. In practice CPython/NumPy here returns length 10 for this exact case, but the point stands: the count is not guaranteed. Never rely on it. Fix: for a known count over an interval, use np.linspace(0, 1, 10, endpoint=False) — deterministic.

L3.2

What does np.linspace(5, 5, 4) return? (Degenerate: start = stop.)

Recall Solution L3.2

. Every point sits on top of the other: array([5., 5., 5., 5.]). No error — linspace happily makes a constant array of length num.

L3.3

What does np.linspace(2, 0, 5) give? (Descending: start > stop.)

Recall Solution L3.3

The formula does not care about direction: , a negative step. [2. , 1.5, 1. , 0.5, 0. ] — counts down, endpoints 2 and 0 both included.

L3.4

Now the arange mirror of L3.3: what does np.arange(2, 0, -0.5) give, and how does the count formula behave when step < 0?

Recall Solution L3.4

WHY the formula still works: with a negative step, both numerator and denominator flip sign. For np.arange(2, 0, -0.5): The two minus signs cancel, so stays positive — exactly what you want (a count can't be negative). Values 2. , 1.5, 1. , 0.5, marching downward, with stop = 0 excluded (just like the ascending case excludes its stop). Sanity check on direction: arange only produces a non-empty array when the step points from start toward stop. np.arange(2, 0, +0.5) would ask "walk up from 2 to reach 0" — impossible, so it returns an empty array of length 0 (the ratio is negative, and NumPy floors the count at 0).


Level 4 — Synthesis

Combine several tools to hit a target result.

L4.1

Build a 1-D array of the odd numbers 1, 3, 5, …, 19 two different ways: once with arange, once by transforming a linspace. Confirm they match.

Recall Solution L4.1

arange way: start 1, step 2, stop just past 19 → np.arange(1, 20, 2). Count . Values 1,3,…,19. ✅ linspace way: 10 evenly spaced points from 1 to 19 (both included): np.linspace(1, 19, 10)1,3,…,19. ✅ Both give the same 10 values. Because came out to a round integer here, linspace is exact.

L4.2

Preallocate a length-6 float buffer with np.zeros, then fill entry with . What is the final array, and why preallocate?

Recall Solution L4.2
out = np.zeros(6)
for i in range(6):
    out[i] = i**3

Result: [ 0., 1., 8., 27., 64., 125.] (floats, because the buffer is float64). WHY preallocate: the buffer is one fixed block of memory. Filling it in place avoids the repeated re-allocation and copying that growing a Python list would incur — the standard fast pattern (see Vectorization vs Python loops).

L4.3

Make a array where every element equals 7 — without using np.full. Then confirm its shape and total.

Recall Solution L4.3

Start from ones and scale: 7 * np.ones((3, 3)). Each of the 9 entries is 7.0. Shape (3, 3). Sum . (np.full((3,3), 7) is the direct route, but scaling np.ones proves you understand that array creators return real arrays you can do arithmetic on.)


Level 5 — Mastery

Full control: reproducibility, statistics, and multi-constraint construction.

L5.1

You set rng = np.random.default_rng(0) and draw a large sample rng.normal(3, 2, 100000). What do you expect for the sample mean and standard deviation, and why can a teammate reproduce your exact numbers?

Recall Solution L5.1

rng.normal(loc, scale, size) draws from a Gaussian with mean loc = 3 and std scale = 2 (Random sampling and distributions). For a large sample the sample mean and sample std (with small random wobble that shrinks as size grows). Reproducibility: the seed 0 fixes the generator's internal state, so default_rng(0) on any machine produces the identical stream of numbers — same mean, same std, byte-for-byte.

L5.2

Design one line that produces the array [0. , 0.2, 0.4, 0.6, 0.8] — five points, step 0.2, but excluding 1.0 — using linspace (not arange, to dodge float drift). Justify the argument choice.

Recall Solution L5.2

Use endpoint=False: np.linspace(0, 1, 5, endpoint=False). WHY: with endpoint=False, linspace treats stop as a phantom fencepost it never keeps, so it divides the interval into num gaps: , giving 0, 0.2, 0.4, 0.6, 0.8. This is the deterministic replacement for the drifty np.arange(0, 1, 0.2).

L5.3

Given rng = np.random.default_rng(0), rng.integers(10, 20, 4) returns four integers. What is the allowed range of each, and could the value 20 ever appear?

Recall Solution L5.3

rng.integers(low, high, size) draws uniform integers in high is exclusive, mirroring arange. So each value is one of 10, 11, 12, …, 19. The value 20 can never appear. (If you needed 20 possible, you'd pass high=21 or set endpoint=True.)


Recall Feynman: the whole ladder in one breath

Two rulers rule everything. linspace = "give me num marks, both ends painted" → gap (b−a)/(num−1). arange = "step by s, stop before the wall" → count ceil((b−a)/s), and a negative s walks downward (two minus signs keep the count positive). Floats crack arange when the step is fractional, so switch to linspace. zeros/ones are blank cartons (shape is one tuple). And default_rng(seed) is dice with a magic replay word.


Connections

  • Parent: Array creation (topic note)
  • NumPy arrays — shape, dtype, ndim
  • Vectorization vs Python loops
  • Array indexing and slicing
  • Reshaping — reshape, ravel, newaxis
  • Plotting functions with Matplotlib
  • Random sampling and distributions
  • Floating-point representation and rounding errors