Python
range function
decimal step
programming
tutorial

How do I use a decimal step value for range?

Interview Questions practice on Codemia

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

Browse interview questions

Introduction

Python built-in range works only with integers, so decimal step values need alternative patterns. The right solution depends on whether you prioritize exact decimal math, NumPy integration, or simple iteration. Choosing intentionally avoids floating-point drift and off-by-one loop boundaries.

Why range Rejects Decimal Steps

range(start, stop, step) is implemented as an efficient integer sequence object. Passing a float step raises TypeError.

python
# TypeError: 'float' object cannot be interpreted as an integer
# range(0, 1, 0.1)

So the practical question is not “how to make range accept float,” but “which non-range approach best matches my precision needs.”

Option 1: Scale Integers, Then Convert

For many loops, integer scaling is the cleanest approach.

python
for i in range(0, 11):
    x = i / 10
    print(x)

This yields values from 0.0 to 1.0 in 0.1 increments without cumulative float addition error. It is usually better than repeatedly adding 0.1 in a while loop.

Option 2: Custom Generator With Float Step

A custom generator gives range-like syntax with decimal steps.

python
1def frange(start: float, stop: float, step: float):
2    if step == 0:
3        raise ValueError("step must not be zero")
4
5    x = start
6    if step > 0:
7        while x < stop:
8            yield x
9            x += step
10    else:
11        while x > stop:
12            yield x
13            x += step
14
15
16for v in frange(0.0, 1.0, 0.1):
17    print(round(v, 4))

Rounding in output is often needed because binary float cannot represent many decimal fractions exactly.

Option 3: Use decimal.Decimal for Exact Financial Steps

If exact decimal representation matters, use Decimal instead of float.

python
1from decimal import Decimal
2
3
4def drange(start: str, stop: str, step: str):
5    s = Decimal(start)
6    e = Decimal(stop)
7    d = Decimal(step)
8
9    if d == 0:
10        raise ValueError("step must not be zero")
11
12    x = s
13    if d > 0:
14        while x < e:
15            yield x
16            x += d
17    else:
18        while x > e:
19            yield x
20            x += d
21
22
23for v in drange("0.0", "1.0", "0.1"):
24    print(v)

This is useful in currency, invoicing, and rules where exact decimal progression is required.

Option 4: NumPy for Numeric Workloads

If you already use NumPy, choose between arange and linspace based on endpoint behavior.

python
1import numpy as np
2
3print(np.arange(0.0, 1.0, 0.1))
4print(np.linspace(0.0, 1.0, 11))

Guideline:

  • arange is step-oriented but can show float drift.
  • linspace is count-oriented and often better when endpoint inclusion matters.

Endpoint and Inclusivity Rules

Define whether stop value should be included. Many bugs come from implicit assumptions.

Examples:

  • frange(0, 1, 0.1) usually excludes 1.0.
  • linspace(0, 1, 11) includes 1.0.

Document this in utility function names or docstrings so call sites are unambiguous.

Performance Considerations

For large numeric arrays, vectorized NumPy operations are much faster than Python loops. For small control-flow loops, plain Python with scaling is often enough and keeps dependencies minimal.

Do not optimize prematurely. Start with clear semantics, then profile if loop volume is high.

Testing Decimal Range Utilities

At minimum, test:

  • Positive and negative steps.
  • Zero-step rejection.
  • Boundary behavior around stop.
  • Expected element count.
python
vals = list(frange(0.0, 0.5, 0.1))
assert len(vals) == 5
assert round(vals[-1], 1) == 0.4

These tests prevent silent changes in iteration semantics.

Common Pitfalls

A common pitfall is using float accumulation for critical decimal logic and expecting exact decimal values. Another issue is unclear endpoint policy, which causes missing or extra loop iterations. Teams also forget to validate zero-step values, leading to infinite loops in custom generators. Using np.arange for strict endpoint inclusion is another frequent mismatch. Finally, mixing float and Decimal values in one pipeline can produce confusing type and precision behavior.

Summary

  • Python range is integer-only and cannot use decimal step directly.
  • Integer scaling is a simple and reliable workaround for many loops.
  • Use Decimal when exact decimal precision is required.
  • Use NumPy linspace or arange based on endpoint needs.
  • Define and test stop-inclusion semantics to avoid off-by-one bugs.

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.