Skip to content
Topics
NumPy
NumPy Arange: How to Create Arrays with Evenly Spaced Values

NumPy Arange: How to Create Arrays with Evenly Spaced Values

Updated on

Creating arrays of evenly spaced numbers is one of the most common operations in scientific computing, data analysis, and machine learning. Whether you need a sequence of indices for a loop, x-axis values for a plot, or grid coordinates for a simulation, you need a fast and reliable way to generate them. Python's built-in range() function works for integers, but it falls apart the moment you need floating-point steps or need the result as a NumPy array for vectorized math.

That is exactly what numpy.arange() solves. It generates arrays of evenly spaced values with full control over the start point, stop point, step size, and data type -- all in a single function call. This guide covers every parameter, walks through practical examples, compares np.arange() with alternatives like range() and np.linspace(), and shows you how to avoid the most common mistakes.

📚

What np.arange() Does

np.arange() returns a one-dimensional NumPy array containing evenly spaced values within a given interval. It is the NumPy equivalent of Python's range(), but it returns an ndarray instead of a range object, and it supports floating-point numbers.

Here is the full function signature:

numpy.arange([start, ] stop, [step, ] dtype=None)

Parameter Reference

ParameterDescriptionDefault
startThe beginning of the interval (inclusive)0
stopThe end of the interval (exclusive)Required
stepThe spacing between consecutive values1
dtypeThe data type of the output array (e.g., int, float, np.float32)Inferred from inputs

The function generates values starting at start and increments by step, stopping before stop is reached. This "exclusive stop" behavior matches Python's range().

Basic Usage: Only the Stop Value

The simplest way to use np.arange() is with a single argument. When you pass one value, it is treated as stop, and start defaults to 0 with a step of 1.

import numpy as np
 
arr = np.arange(5)
print(arr)
# Output: [0 1 2 3 4]
 
print(type(arr))
# Output: <class 'numpy.ndarray'>

This creates an array of integers from 0 up to (but not including) 5. Notice that the result is a NumPy ndarray, not a Python list. That means you can immediately use it in vectorized operations:

import numpy as np
 
arr = np.arange(5)
print(arr * 10)
# Output: [ 0 10 20 30 40]
 
print(arr ** 2)
# Output: [ 0  1  4  9 16]

Using Start and Stop

Pass two arguments to control where the sequence begins and ends:

import numpy as np
 
arr = np.arange(2, 10)
print(arr)
# Output: [2 3 4 5 6 7 8 9]

The array starts at 2 (inclusive) and stops before 10 (exclusive). The default step is still 1.

You can also use negative start values:

import numpy as np
 
arr = np.arange(-3, 4)
print(arr)
# Output: [-3 -2 -1  0  1  2  3]

Using Start, Stop, and Step

The third argument controls the spacing between values. This is where np.arange() becomes much more powerful than range(), because the step can be a float:

import numpy as np
 
arr = np.arange(0, 1, 0.1)
print(arr)
# Output: [0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]

Integer steps work the same way:

import numpy as np
 
arr = np.arange(0, 20, 3)
print(arr)
# Output: [ 0  3  6  9 12 15 18]

The step can be any positive number. The sequence always stops before reaching the stop value.

Float Step Sizes and Precision Issues

Using floating-point step sizes is convenient, but it comes with a caveat: floating-point arithmetic is not exact. Small rounding errors can accumulate and occasionally produce unexpected results.

Consider this example:

import numpy as np
 
arr = np.arange(0, 1, 0.3)
print(arr)
# Output: [0.  0.3 0.6 0.9]
 
print(len(arr))
# Output: 4

This looks correct. But watch what happens with certain step sizes:

import numpy as np
 
arr = np.arange(0, 1.0, 0.1)
print(len(arr))
# Output: 10
 
arr2 = np.arange(0.0, 1.0 + 1e-10, 0.1)
print(len(arr2))
# Output: 11

Due to floating-point representation, 0.1 * 10 might not equal exactly 1.0 in binary. The number of elements in the result can vary by one depending on the specific values.

Best practice: When you need an exact number of evenly spaced floating-point values, use np.linspace() instead. Use np.arange() for floating-point sequences only when the exact count of elements does not matter.

Negative Steps: Counting Down

Set a negative step to create a descending sequence:

import numpy as np
 
arr = np.arange(10, 0, -1)
print(arr)
# Output: [10  9  8  7  6  5  4  3  2  1]

A float step works the same way:

import numpy as np
 
arr = np.arange(2.0, 0.0, -0.5)
print(arr)
# Output: [2.  1.5 1.  0.5]

The key rule: the step direction must match the direction from start to stop. If start < stop, step must be positive. If start > stop, step must be negative. Getting this wrong produces an empty array (covered in the errors section below).

The dtype Parameter

By default, np.arange() infers the data type from the arguments you pass. If all arguments are integers, you get an integer array. If any argument is a float, you get a float array. The dtype parameter lets you override this:

import numpy as np
 
# Default: integers in, integers out
arr_int = np.arange(5)
print(arr_int.dtype)
# Output: int64
 
# Default: float step, float output
arr_float = np.arange(0, 5, 0.5)
print(arr_float.dtype)
# Output: float64
 
# Force float output from integer inputs
arr_forced = np.arange(5, dtype=np.float32)
print(arr_forced)
# Output: [0. 1. 2. 3. 4.]
print(arr_forced.dtype)
# Output: float32
 
# Force integer output (values get truncated)
arr_trunc = np.arange(0, 2, 0.5, dtype=int)
print(arr_trunc)
# Output: [0 0 1 1]

Notice the last example: when you force an integer dtype on a float sequence, each value is truncated (not rounded) to an integer. This can produce duplicate values and unexpected results, so use it carefully.

np.arange() vs range(): When to Use Each

Python's built-in range() and NumPy's np.arange() both generate sequences of numbers, but they serve different purposes.

Featurerange()np.arange()
Return typerange object (lazy iterator)numpy.ndarray (in memory)
Supports floatsNo (integers only)Yes
Vectorized mathNo (need list conversion)Yes (direct array operations)
MemoryVery low (generates on demand)Array stored in memory
Speed for iterationFast for Python loopsSlower for Python loops
Speed for mathSlow (must convert first)Fast (vectorized C operations)
Use in NumPy/SciPyMust convert with np.array()Works directly
Slice/index resultReturns range objectReturns ndarray

When to use range(): Pure Python loops where you need indices, and you are not doing any math on the sequence itself.

When to use np.arange(): Any time the result will be used in numerical computation, passed to a NumPy/SciPy function, or needs to contain floating-point values.

import numpy as np
 
# range() for loop iteration
for i in range(5):
    print(i, end=' ')
# Output: 0 1 2 3 4
 
print()
 
# np.arange() for vectorized math
x = np.arange(5)
print(np.sin(x))
# Output: [ 0.          0.84147098  0.90929743  0.14112001 -0.7568025 ]

np.arange() vs np.linspace(): When to Use Each

Both functions create arrays of evenly spaced values, but they define the spacing differently.

Featurenp.arange()np.linspace()
You specifyStep sizeNumber of points
Stop valueExcluded by defaultIncluded by default
Float precisionCan produce unexpected element countsAlways produces exact count
Typical useInteger sequences, known step sizeExact number of points in a range
Syntaxnp.arange(start, stop, step)np.linspace(start, stop, num)
Returns count infoNoOptional (retstep=True)

Here is a side-by-side example that shows the difference clearly:

import numpy as np
 
# arange: "give me values from 0 to 1, stepping by 0.2"
a = np.arange(0, 1, 0.2)
print(f"arange: {a}  (length: {len(a)})")
# Output: arange: [0.  0.2 0.4 0.6 0.8]  (length: 5)
 
# linspace: "give me exactly 6 values from 0 to 1"
b = np.linspace(0, 1, 6)
print(f"linspace: {b}  (length: {len(b)})")
# Output: linspace: [0.  0.2 0.4 0.6 0.8 1. ]  (length: 6)

Notice that np.linspace() includes the endpoint (1.0) and guarantees exactly 6 values, while np.arange() stops before 1.0 and the count depends on the floating-point step calculation.

Rule of thumb: Use np.arange() when you care about the step size. Use np.linspace() when you care about the number of points.

Common Use Cases

Loop Indices and Array Indexing

import numpy as np
 
data = np.array([10, 20, 30, 40, 50])
indices = np.arange(len(data))
 
print(indices)
# Output: [0 1 2 3 4]
 
# Use for conditional selection
mask = indices % 2 == 0
print(data[mask])
# Output: [10 30 50]

Plotting X-Axis Values

import numpy as np
 
x = np.arange(0, 2 * np.pi, 0.01)
y = np.sin(x)
 
print(f"x has {len(x)} points, from {x[0]:.2f} to {x[-1]:.2f}")
# Output: x has 629 points, from 0.00 to 6.28
print(f"y ranges from {y.min():.4f} to {y.max():.4f}")
# Output: y ranges from -1.0000 to 1.0000

You can pass x and y directly to matplotlib's plt.plot(x, y) to draw a smooth sine wave.

Creating Grid Coordinates

import numpy as np
 
x = np.arange(0, 3)
y = np.arange(0, 4)
xx, yy = np.meshgrid(x, y)
 
print("xx:")
print(xx)
# Output:
# [[0 1 2]
#  [0 1 2]
#  [0 1 2]
#  [0 1 2]]
 
print("yy:")
print(yy)
# Output:
# [[0 0 0]
#  [1 1 1]
#  [2 2 2]
#  [3 3 3]]

This pattern is used extensively in image processing, heat maps, and 3D surface plots.

Generating Time-Based Sequences

import numpy as np
 
# Hours from 0 to 24 in 30-minute intervals
hours = np.arange(0, 24.5, 0.5)
print(f"Time points: {len(hours)}")
# Output: Time points: 49
print(hours[:6])
# Output: [0.  0.5 1.  1.5 2.  2.5]

Common Errors and How to Fix Them

Empty Array from Wrong Step Direction

The most frequent mistake with np.arange() is using a step that goes in the wrong direction:

import numpy as np
 
# Trying to count down with a positive step
arr = np.arange(10, 0, 1)
print(arr)
# Output: []
 
# Trying to count up with a negative step
arr2 = np.arange(0, 10, -1)
print(arr2)
# Output: []

Both return an empty array with no error or warning. The fix is straightforward -- make sure the step direction matches the direction from start to stop:

import numpy as np
 
# Correct: counting down with negative step
arr = np.arange(10, 0, -1)
print(arr)
# Output: [10  9  8  7  6  5  4  3  2  1]

Zero Step Size

A step of 0 is never valid and raises an error:

import numpy as np
 
try:
    arr = np.arange(0, 10, 0)
except ZeroDivisionError as e:
    print(f"Error: {e}")
# Output: Error: division by zero

Unexpectedly Large Arrays

Because np.arange() creates the entire array in memory at once, a very small step over a large range can consume gigabytes of RAM:

import numpy as np
 
# This creates 10 billion elements -- do NOT run this
# arr = np.arange(0, 10, 0.000000001)
 
# Check the size first
count = int((10 - 0) / 0.000000001)
print(f"This would create {count:,} elements")
# Output: This would create 10,000,000,000 elements
print(f"Memory: ~{count * 8 / 1e9:.1f} GB (for float64)")
# Output: Memory: ~80.0 GB (for float64)

Always estimate the size before generating large sequences.

Experiment with NumPy in RunCell

If you want to try these examples interactively and get AI-powered assistance while learning NumPy, check out RunCell (opens in a new tab). RunCell is an AI agent built directly into Jupyter that helps data scientists write, debug, and optimize code.

Instead of switching between documentation tabs and your notebook, you can ask RunCell to generate np.arange() examples, explain floating-point precision behavior, or help you choose between arange and linspace for your specific use case. It runs right inside your existing Jupyter environment, so there is no setup friction -- just install and start asking questions next to your code cells.

This is particularly useful when you are exploring NumPy array creation functions for the first time, because you can iterate on examples in real time and see results immediately.

FAQ

What does numpy arange return?

np.arange() returns a one-dimensional NumPy ndarray containing evenly spaced values. Unlike Python's range(), which returns a lazy iterator, np.arange() generates the full array in memory. The array supports vectorized operations, broadcasting, and all standard NumPy functions.

Can numpy arange use float step values?

Yes. Unlike Python's range(), which only accepts integers, np.arange() fully supports floating-point start, stop, and step values. For example, np.arange(0, 1, 0.1) generates [0.0, 0.1, 0.2, ..., 0.9]. However, be aware that floating-point rounding can occasionally cause the result to have one more or one fewer element than expected. Use np.linspace() when you need a guaranteed number of elements.

What is the difference between np.arange and np.linspace?

np.arange() takes a step size and generates values until it reaches the stop value (exclusive). np.linspace() takes the number of points you want and calculates the step size automatically, including the endpoint by default. Use arange when you know the step size. Use linspace when you know how many points you need.

Why does np.arange return an empty array?

An empty array is returned when the step direction does not match the direction from start to stop. For example, np.arange(10, 0, 1) returns an empty array because a positive step cannot move from 10 down to 0. The fix is to use a negative step: np.arange(10, 0, -1).

Is np.arange inclusive or exclusive of the stop value?

The stop value is exclusive -- it is never included in the output. np.arange(0, 5) returns [0, 1, 2, 3, 4], not [0, 1, 2, 3, 4, 5]. This matches the behavior of Python's built-in range(). If you need the endpoint included, use np.linspace() with endpoint=True (the default).

Conclusion

np.arange() is one of NumPy's most-used functions for a reason: it is the fastest way to generate arrays of evenly spaced numbers in Python. Here is a summary of what to remember:

  • One argument (np.arange(n)) creates integers from 0 to n-1.
  • Two arguments (np.arange(start, stop)) define the range with a default step of 1.
  • Three arguments (np.arange(start, stop, step)) give full control, including float steps and negative steps for descending sequences.
  • dtype overrides automatic type inference when you need a specific data type.
  • Use np.arange() when you care about the step size. Use np.linspace() when you care about the number of points.
  • Watch out for float precision -- np.arange() with float steps may produce an unexpected number of elements.
  • Empty arrays result from a mismatch between step direction and the start-to-stop direction.

For interactive experimentation with NumPy arrays, RunCell (opens in a new tab) provides AI-assisted coding directly in Jupyter, letting you test np.arange() variants and get instant explanations without leaving your notebook.

📚