Rounding & Clipping

Reviewed & published by Brayan K

Rounding and clipping are the tools for tidying numeric arrays — rounding controls how many decimals you keep, while clipping caps every value into a valid range so outliers cannot escape.

Part of the free NumPy course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

You'll round to decimals, floor and ceil to integers, truncate toward zero, clip values into bounds, and read signs with np.sign.

What You'll Learn in This Lesson

1 np.round and the Decimals Argument

np.round(arr, decimals) rounds to the nearest value at the chosen number of decimal places (np.around is the same function). One quirk: NumPy uses banker's rounding — exact halves round to the nearest even number, so 0.5 rounds to 0 and 2.5 rounds to 2.

import numpy as np

arr = np.array([1.234, 2.567, 3.891])
np.round(arr, 1)      # [1.2 2.6 3.9]
np.round(arr)         # [1. 3. 4.]

# Banker's rounding: ties go to the even number
np.round([0.5, 1.5, 2.5, 3.5])   # [0. 2. 2. 4.]
import numpy as np

arr = np.array([1.234, 2.567, 3.891])

print(np.round(arr, 1))        # [1.2 2.6 3.9]
print(np.round(arr, 2))        # [1.23 2.57 3.89]
print(np.round(arr))           # [1. 3. 4.]

# Banker's rounding: halves go to the nearest even
print(np.round([0.5, 1.5, 2.5, 3.5]))   # [0. 2. 2. 4.]

# ✅ Expected output:
# [1.2 2.6 3.9]
# [1.23 2.57 3.89]
# [1. 3. 4.]
# [0. 2. 2. 4.]

2 floor, ceil & trunc

These three always go to an integer but in different directions. np.floor rounds down, np.ceil rounds up, and np.trunc chops off the fraction toward zero. The difference only shows on negative numbers.

vals = np.array([2.7, -2.7])

np.floor(vals)   # [ 2. -3.]   -> down (more negative)
np.ceil(vals)    # [ 3. -2.]   -> up (more positive)
np.trunc(vals)   # [ 2. -2.]   -> toward zero (drops fraction)
import numpy as np

vals = np.array([2.3, 2.7, -2.3, -2.7])

print(np.floor(vals))      # [ 2.  2. -3. -3.]
print(np.ceil(vals))       # [ 3.  3. -2. -2.]
print(np.trunc(vals))      # [ 2.  2. -2. -2.]

# floor vs trunc differ only for negatives
print(np.floor(-2.7), np.trunc(-2.7))   # -3.0 -2.0

# ✅ Expected output:
# [ 2.  2. -3. -3.]
# [ 3.  3. -2. -2.]
# [ 2.  2. -2. -2.]
# -3.0 -2.0

3 np.clip and np.sign

np.clip(arr, low, high) caps every value into a range: anything below low becomes low, anything above high becomes high. It is the cleanest way to limit outliers. np.sign returns -1, 0, or 1 to capture the direction of each value.

scores = np.array([-5, 30, 75, 130])

np.clip(scores, 0, 100)    # [ 0 30 75 100]  -> capped to 0..100

np.sign([-8, 0, 4])        # [-1  0  1]

# Use None to clip on one side only
np.clip(scores, 0, None)   # [ 0 30 75 130]  -> floor at 0, no ceiling
import numpy as np

scores = np.array([-5, 30, 75, 130])

# Cap everything into the valid 0..100 range
print(np.clip(scores, 0, 100))     # [  0  30  75 100]

# Clip only the lower bound with None as the upper
print(np.clip(scores, 0, None))    # [  0  30  75 130]

# Direction of each value
print(np.sign([-8, 0, 4]))         # [-1  0  1]

# ✅ Expected output:
# [  0  30  75 100]
# [  0  30  75 130]
# [-1  0  1]

🎯 YOUR TURN: Fill in the Blank

Replace ___ with the bounds that keep every value between 0 and 10.

import numpy as np

data = np.array([-3, 0, 5, 12, 20])

# 🎯 YOUR TURN:
# Cap the values so nothing is below 0 or above 10.
# Hint: np.clip(arr, low, high)
result = np.clip(data, ___, ___)

print(result)
# Expected output:
# [ 0  0  5 10 10]

Answer: 0, 10 — values below 0 become 0 and values above 10 become 10.

! Common Errors (And How to Fix Them)

❌ Surprised that np.round(2.5) gives 2

NumPy uses banker's rounding, sending halves to the even number:

np.round([0.5, 1.5, 2.5])   # [0. 2. 2.]  not [1. 2. 3.]

✅ Fix: if you need always-up rounding, add a tiny offset or use np.floor(x + 0.5) deliberately.

❌ floor vs trunc on negatives

np.floor(-1.2)   # -2.0   (down)
np.trunc(-1.2)   # -1.0   (toward zero)

✅ Fix: choose floor for "round down" and trunc for "drop the fraction".

❌ Swapping clip's min and max

np.clip(arr, 100, 0)   # ❌ low > high gives surprising results

✅ Fix: pass the smaller bound first: np.clip(arr, 0, 100).

🎯 Mini Challenge: Tidy a Price List

Round raw prices to 2 decimals, then clip any negative or sky-high values into a sensible 0 to 100 range.

import numpy as np

raw = np.array([-1.0, 12.345, 67.899, 150.0])

# Round to cents (NumPy uses banker's rounding, so 12.345 -> 12.34)
rounded = np.round(raw, 2)
print(rounded)                 # [ -1.    12.34  67.9  150.  ]

# Clip into a valid 0..100 price range
final = np.clip(rounded, 0, 100)
print(final)                   # [  0.    12.34  67.9  100.  ]

# ✅ Expected output:
# [ -1.    12.34  67.9  150.  ]
# [  0.    12.34  67.9  100.  ]

❓ Frequently Asked Questions

Lesson complete — numbers tidied!

You can round to decimals with np.round, snap to integers with floor/ceil/trunc, cap outliers with np.clip, and read direction with np.sign.

Practice quiz

What does np.round([0.5, 1.5, 2.5, 3.5]) return?

  • [1. 2. 3. 4.]
  • [0. 2. 2. 4.]
  • [0. 1. 2. 3.]
  • [1. 2. 2. 4.]

Answer: [0. 2. 2. 4.]. NumPy uses banker's rounding, sending halves to the nearest even number.

What does np.floor(2.7) return?

  • 3.0
  • 2.7
  • -3.0
  • 2.0

Answer: 2.0. floor always rounds down to the integer below, giving 2.0.

What does np.ceil(2.3) return?

  • 3.0
  • 2.0
  • 2.3
  • -2.0

Answer: 3.0. ceil always rounds up to the integer above, giving 3.0.

What does np.floor(-2.7) return?

  • -2.0
  • 2.0
  • -3.0
  • 3.0

Answer: -3.0. floor rounds down (more negative), so -2.7 becomes -3.0.

What does np.trunc(-2.7) return?

  • -3.0
  • -2.0
  • 3.0
  • 2.0

Answer: -2.0. trunc drops the fraction toward zero, so -2.7 becomes -2.0.

What does np.clip([-5, 30, 75, 130], 0, 100) return?

  • [-5 30 75 130]
  • [0 30 75 130]
  • [5 30 75 100]
  • [0 30 75 100]

Answer: [0 30 75 100]. Values below 0 become 0 and above 100 become 100.

What does np.sign([-8, 0, 4]) return?

  • [-1 0 1]
  • [8 0 4]
  • [1 0 -1]
  • [-8 0 4]

Answer: [-1 0 1]. sign returns -1 for negatives, 0 for zero, and 1 for positives.

What does np.clip(scores, 0, None) do?

  • Clips both ends to 0
  • Raises an error
  • Floors at 0 with no upper limit
  • Removes all values

Answer: Floors at 0 with no upper limit. None as the upper bound means clip only the lower side at 0.

After np.round with the default decimals=0, what type are the results?

  • strings
  • floats like 1.
  • true integers
  • booleans

Answer: floats like 1.. Rounding returns floats (1.), so cast with .astype(int) for integers.

When does np.floor differ from np.trunc?

  • For very large numbers
  • For zero
  • Never
  • Only for negative numbers

Answer: Only for negative numbers. They agree on positives; on negatives floor goes down while trunc goes toward zero.

Continue this course

Frequently asked questions

What is the difference between np.round, np.floor, and np.ceil?

np.round rounds to the nearest value (and to a chosen number of decimals), np.floor always rounds DOWN to the integer below, and np.ceil always rounds UP to the integer above. np.trunc simply drops the fractional part toward zero. So for 2.7: round gives 3, floor gives 2, ceil gives 3, and trunc gives 2.

Why does np.round(0.5) give 0 instead of 1?

NumPy uses 'round half to even' (also called banker's rounding) to reduce statistical bias. When a value is exactly halfway, it rounds to the nearest even number, so 0.5 becomes 0 and 2.5 becomes 2, while 1.5 and 3.5 both become 2 and 4. This surprises people expecting 'always round half up', but it is the IEEE standard.

What does np.clip do?

np.clip(arr, low, high) limits every value to the range [low, high]: anything below low becomes low, anything above high becomes high, and values inside the range are left alone. It is the standard way to cap outliers or keep values within valid bounds without writing conditionals.

What does np.sign return?

np.sign returns -1 for negative numbers, 0 for zero, and 1 for positive numbers, element-wise. It is handy for extracting the direction of values, for example to separate gains from losses, or to multiply a magnitude back by its original sign.