Chapter 4: Rounding Decimals
1. Why rounding decimals matters (and why NumPy makes it tricky)
When we work with floating-point numbers in NumPy, we almost always need to round them at some point:
- For beautiful reports and tables (nobody wants 12.3456789012345 in output)
- For display purposes (charts, dashboards, print statements)
- For saving storage (float64 → float32 after rounding)
- For comparison (rounded values are easier to match)
- For model output post-processing (many APIs expect 2–4 decimal places)
- For avoiding floating-point noise (0.30000000000000004 → 0.3)
But rounding is not trivial in NumPy because there are several functions, they behave slightly differently, and they interact with bankers’ rounding (round-to-even).
2. The four main rounding functions you need to know
NumPy gives you these four important rounding ufuncs:
| Function | What it does | Returns | Common use case | Bankers’ rounding? |
|---|---|---|---|---|
| np.round() | Round to nearest, ties to even (default) | new array | General-purpose rounding | Yes |
| np.rint() | Round to nearest integer, ties to even | new array | Same as round(…, decimals=0) | Yes |
| np.floor() | Always round down (towards -∞) | new array | Lower bound, flooring ages/prices | No |
| np.ceil() | Always round up (towards +∞) | new array | Upper bound, ceiling required items | No |
| np.trunc() | Truncate (remove decimal part, towards zero) | new array | Remove fractional part without rounding | No |
3. Let’s see them side by side – most important examples
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
values = np.array([ -3.7, -2.3, -1.8, -0.6, -0.4, 0.0, 0.4, 0.6, 1.2, 1.7, 2.3, 3.8 ]) print("Original values:") print(values) print("\nnp.round (to nearest integer):") print(np.round(values)) print("\nnp.rint (same as round to integer):") print(np.rint(values)) print("\nnp.floor (always down):") print(np.floor(values)) print("\nnp.ceil (always up):") print(np.ceil(values)) print("\nnp.trunc (cut off decimal):") print(np.trunc(values)) |
Typical output:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Original values: [-3.7 -2.3 -1.8 -0.6 -0.4 0. 0.4 0.6 1.2 1.7 2.3 3.8] np.round: [-4. -2. -2. -1. 0. 0. 0. 1. 1. 2. 2. 4.] np.rint: [-4. -2. -2. -1. 0. 0. 0. 1. 1. 2. 2. 4.] np.floor: [-4. -3. -2. -1. -1. 0. 0. 0. 1. 1. 2. 3.] np.ceil: [-3. -2. -1. 0. 0. 0. 1. 1. 2. 2. 3. 4.] np.trunc: [-3. -2. -1. -0. -0. 0. 0. 0. 1. 1. 2. 3.] |
Important observations:
- round and rint use round-to-even (bankers’ rounding)
- 1.5 → 2, 2.5 → 2, 3.5 → 4, 4.5 → 4
- floor always goes down (more negative for negatives)
- ceil always goes up (more positive)
- trunc just removes decimals (towards zero)
4. Rounding to specific number of decimal places
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
numbers = np.array([ 123.45678, 9.876543, 0.123456, 5.555555, 2.500001, -3.499999 ]) print("Original:") print(numbers) print("\nRound to 2 decimal places:") print(np.round(numbers, decimals=2)) print("\nRound to 0 decimal places (integer):") print(np.round(numbers, decimals=0)) print("\nRound to -1 (tens place):") print(np.round(numbers, decimals=-1)) |
Output highlights:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
Round to 2 decimals: [123.46 9.88 0.12 5.56 2.5 -3.5 ] Round to 0 decimals: [123. 10. 0. 6. 2. -3.] Round to -1 (tens): [120. 10. 0. 0. 0. -0.] |
Student trap — decimals=-1 rounds to the nearest 10, -2 to nearest 100, etc.
5. Realistic patterns you will use again and again
Pattern 1 – Clean display values for reports
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
sales = np.random.uniform(1000, 9999, 8) growth = np.random.uniform(-0.25, 0.45, 8) report = np.column_stack([sales, growth * 100]) # Round for nice printing report_rounded = np.round(report, decimals=[0, 2]) # sales whole, growth 2 decimals print("Sales ($) Growth (%)") print(report_rounded) |
Pattern 2 – Clip & round sensor readings
|
0 1 2 3 4 5 6 7 8 9 10 |
raw_readings = np.random.normal(25, 3, 20) # Realistic temperature: round to 1 decimal, bound 15–35 °C cleaned = np.round(np.clip(raw_readings, 15, 35), 1) print(cleaned) |
Pattern 3 – Round probabilities / percentages
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
probs = np.random.dirichlet(np.ones(5), size=10) # random probabilities # Round to 3 decimals, make sure they still sum ≈ 1 probs_rounded = np.round(probs, 3) # Fix possible rounding error in last column probs_rounded[:, -1] = 1 - probs_rounded[:, :-1].sum(axis=1) print(probs_rounded.round(3)) |
Pattern 4 – Round before saving to database / CSV
|
0 1 2 3 4 5 6 7 8 9 10 11 |
data = np.random.randn(1000, 4) * 100 + 5000 # pretend prices # Round prices to 2 decimals before saving data_rounded = np.round(data, 2) # np.savetxt("prices.csv", data_rounded, fmt="%.2f", delimiter=",") |
Summary – Rounding Functions Quick Reference
| Function | Behavior | Use when you want… |
|---|---|---|
| np.round | nearest, ties to even | most general-purpose rounding |
| np.rint | nearest integer, ties to even | equivalent to round(…, decimals=0) |
| np.floor | always down (towards -∞) | lower bound, flooring |
| np.ceil | always up (towards +∞) | upper bound, ceiling |
| np.trunc | cut off decimal part (towards zero) | remove fractional part without rounding |
| np.around | alias of np.round | same as round |
Final teacher advice (very important)
Golden rule #1 Use np.round for almost everything unless you have a specific reason to use floor/ceil/trunc.
Golden rule #2 When displaying numbers (print, report, chart labels) → round early (before saving/showing).
Golden rule #3 Be careful with negative numbers — floor and ceil behave opposite to intuition:
- floor(-2.3) = -3 (goes more negative)
- ceil(-2.3) = -2 (goes less negative)
Golden rule #4 np.round uses bankers’ rounding (ties round to nearest even) — this surprises people coming from Excel or school.
Would you like to continue with any of these next?
- Rounding pitfalls with floating-point precision
- How to round to significant figures (not just decimals)
- Rounding before/after aggregation (mean, sum, etc.)
- Realistic mini-project: clean & round financial / sensor data
- Difference between round / rint / around
Just tell me what you want to focus on next! 😊
