Python
Floats
range function
Programming
Iteration

range for floats

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Python's built-in range() only works with integers. To generate a sequence of floating-point numbers, use numpy.arange() for NumPy-based workflows, numpy.linspace() for evenly spaced points between endpoints, or a custom generator function. The most reliable approach is numpy.linspace() because it avoids the floating-point accumulation errors that affect step-based methods.

Why range() Does Not Support Floats

python
1# range() only accepts integers
2for i in range(0, 1, 0.1):
3    print(i)
4# TypeError: 'float' object cannot be interpreted as an integer
5
6# range is designed for integer sequences
7list(range(0, 10, 2))  # [0, 2, 4, 6, 8]

Python's range() is strictly integer-based because floating-point arithmetic introduces rounding errors that make it impossible to guarantee the exact number of elements in the sequence.

Method 1: numpy.arange()

python
1import numpy as np
2
3# Like range() but for floats
4values = np.arange(0.0, 1.0, 0.1)
5print(values)
6# [0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]
7
8# Negative step
9values = np.arange(1.0, 0.0, -0.2)
10print(values)
11# [1.  0.8 0.6 0.4 0.2]
12
13# CAUTION: floating-point rounding can include/exclude the endpoint
14values = np.arange(0.0, 1.0 + 1e-10, 0.1)  # add epsilon to include 1.0
15print(len(values))  # 11

numpy.arange follows the same start/stop/step convention as range. The stop value is exclusive, but floating-point rounding can produce unexpected results near the boundary.

python
1import numpy as np
2
3# Generate exactly 11 points from 0.0 to 1.0 (inclusive)
4values = np.linspace(0.0, 1.0, num=11)
5print(values)
6# [0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0]
7
8# Exclusive endpoint
9values = np.linspace(0.0, 1.0, num=10, endpoint=False)
10print(values)
11# [0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]
12
13# Arbitrary range
14values = np.linspace(-5.0, 5.0, num=21)
15# [-5.0, -4.5, -4.0, ..., 4.5, 5.0]

linspace is preferred over arange because you specify the number of points instead of the step size. This guarantees the exact number of elements and always includes the endpoint (unless endpoint=False).

Method 3: Custom Generator (No NumPy)

python
1def frange(start, stop, step):
2    """Generate float range without NumPy."""
3    current = start
4    if step > 0:
5        while current < stop:
6            yield round(current, 10)  # round to avoid accumulation errors
7            current += step
8    else:
9        while current > stop:
10            yield round(current, 10)
11            current += step
12
13# Usage
14for x in frange(0.0, 1.0, 0.1):
15    print(f"{x:.1f}", end=" ")
16# 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9
17
18# Negative step
19list(frange(1.0, 0.0, -0.25))
20# [1.0, 0.75, 0.5, 0.25]

A custom generator avoids the NumPy dependency but requires careful rounding to prevent floating-point drift.

Method 4: Multiplication-Based (Most Accurate Without NumPy)

python
1def frange_precise(start, stop, step):
2    """Use integer counting to avoid float accumulation errors."""
3    n = int(round((stop - start) / step))
4    for i in range(n):
5        yield start + i * step
6
7# No accumulation error — each value is computed from the base
8for x in frange_precise(0.0, 1.0, 0.1):
9    print(f"{x:.15f}")
10# 0.000000000000000
11# 0.100000000000000
12# 0.200000000000000
13# ...
14# 0.900000000000000

Computing each value as start + i * step avoids the accumulation error that occurs when repeatedly adding step to a running total.

Method 5: Using decimal for Exact Arithmetic

python
1from decimal import Decimal
2
3def frange_decimal(start, stop, step):
4    start = Decimal(str(start))
5    stop = Decimal(str(stop))
6    step = Decimal(str(step))
7    current = start
8    while current < stop:
9        yield float(current)
10        current += step
11
12# Exact results — no floating-point errors
13values = list(frange_decimal(0.0, 1.0, 0.1))
14print(values)
15# [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
16print(len(values))  # Always 10

Decimal provides exact decimal arithmetic, eliminating the floating-point rounding issues that plague float-based approaches.

Floating-Point Accumulation Error

python
1# Why simple addition goes wrong
2total = 0.0
3for _ in range(10):
4    total += 0.1
5print(f"{total:.20f}")
6# 0.99999999999999988898 — not exactly 1.0
7print(total == 1.0)  # False!
8
9# After many iterations, the error grows
10total = 0.0
11for _ in range(1000):
12    total += 0.001
13print(f"{total:.20f}")
14# 0.99999999999999833467 — noticeable drift after 1000 additions

0.1 cannot be represented exactly in binary floating-point. Each addition introduces a tiny error, and these errors accumulate over many iterations.

Comparison Table

MethodRequires NumPyEndpoint ControlAccuracyMemory
numpy.arangeYesExclusive (unreliable at boundary)GoodArray
numpy.linspaceYesInclusive/exclusiveBestArray
Custom generatorNoExclusiveNeeds roundingLazy
Multiplication-basedNoExclusiveVery goodLazy
Decimal-basedNoExclusiveExactLazy

Common Pitfalls

  • Assuming numpy.arange includes or excludes the endpoint predictably: Due to floating-point rounding, np.arange(0, 1.0, 0.1) may produce 10 or 11 elements depending on the platform. Use linspace for deterministic element counts.
  • Accumulating step values with +=: Repeatedly adding 0.1 to a float causes drift. After 10 additions, the result is 0.9999999... instead of 1.0. Use multiplication (start + i * step) or Decimal for accuracy.
  • Using range() with float arguments: range() raises TypeError for float arguments. This is by design — there is no way to guarantee integer-like behavior with floats.
  • Not specifying num correctly in linspace: np.linspace(0, 1, 10) produces 10 points with endpoint 1.0 included. If you expect steps of 0.1, you need num=11 (10 intervals = 11 points). Off-by-one errors are common.
  • Using a float range for equality comparisons: Comparing floats with == after generating them via a range is unreliable. Use math.isclose() or a tolerance check: abs(a - b) < 1e-9.

Summary

  • Python's range() only supports integers — use numpy.arange() or numpy.linspace() for float sequences
  • numpy.linspace(start, stop, num) is the most reliable because you specify the number of points, not the step size
  • For no-NumPy solutions, use multiplication-based generation (start + i * step) to avoid float accumulation errors
  • Use Decimal for exact decimal arithmetic when precision is critical
  • Never compare float range values with == — use math.isclose() or tolerance-based comparisons
  • numpy.arange endpoint inclusion is unpredictable — prefer linspace for deterministic results

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.