Data types (dtypes) & memory

Every NumPy array has a single dtype that decides how each element is stored in memory. Picking the right one can shrink a dataset several times over, and picking the wrong one can silently give wrong answers.

Common dtypes

dtype Bytes per value Range / precision Typical use
int8 1 -128 to 127 Small codes, ratings 1–5
int32 4 about ±2.1 billion Counts, IDs
int64 8 about ±9.2 x 10^18 Default integer on most platforms
float32 4 ~7 significant digits ML features, images
float64 8 ~15–16 significant digits Default float, finance, science
bool 1 True / False Masks

Inspecting and converting

import numpy as np

qty = np.array([3, 5, 2, 8])
print(qty.dtype, qty.itemsize, qty.nbytes)   # int64 8 32

qty_small = qty.astype(np.int16)
print(qty_small.nbytes)                      # 8

prices = np.array([199.0, 249.5, 99.9], dtype=np.float32)
print(np.iinfo(np.int16).max)                # 32767
print(np.finfo(np.float32).eps)              # machine precision of float32

astype always returns a new array, so assign the result back.

Memory at scale

One crore (10 million) sensor readings:

n = 10_000_000
print(np.zeros(n, dtype=np.float64).nbytes / 1e6)   # 80.0 MB
print(np.zeros(n, dtype=np.float32).nbytes / 1e6)   # 40.0 MB
print(np.zeros(n, dtype=np.int8).nbytes / 1e6)      # 10.0 MB

For store IDs between 0 and 500, int16 is plenty. For temperatures to one decimal place, float32 is enough.

Trap 1: integer overflow wraps silently

Array arithmetic does not check for overflow. It simply wraps around:

stock = np.array([100, 120], dtype=np.int8)
print(stock + stock)        # [-56 -16]  -- wrong, no error raised!

Always check np.iinfo(dtype) limits before downcasting, especially for sums and products, which grow fast.

Trap 2: floating-point precision

Binary floats cannot represent most decimals exactly:

print(0.1 + 0.2 == 0.3)               # False
print(np.isclose(0.1 + 0.2, 0.3))     # True

Compare floats with np.isclose or np.allclose, never ==. For money, many teams store paise as integers (₹249.50 becomes 24950) to avoid rounding drift in totals.

Trap 3: upcasting in mixed operations

Combining dtypes promotes to a type that can hold both, so an int8 array plus a float64 array gives float64. Your carefully small array can quietly become large again.

Strings and objects

np.array(["Pune", "Delhi"]) creates a fixed-width Unicode dtype such as <U5, sized to the longest string. Mixed Python objects give dtype=object, which loses NumPy's speed because every element is a Python object. For text-heavy data, pandas is usually the better tool.

Key takeaways

  • Check dtype, itemsize and nbytes when memory matters.
  • Downcast only after checking value ranges with np.iinfo / np.finfo.
  • Integer overflow in arrays is silent; floats are approximate.
  • Avoid object arrays for numerical work.

Practice

Create an array of 1,000,000 random exam marks between 0 and 100. Store it as int64, then as the smallest safe integer dtype, and print the memory saved. Then show what goes wrong if you sum the marks in int16 versus int64.

B

Written by Bablu Kumar Jha

Founder, BeeProton AI · Mumbai, Maharashtra, India