Angka int dan float pada Python murni bersifat fleksibel: satu objek Python dapat tumbuh sebesar apa pun memori yang tersedia. Fleksibilitas itu ada harganya, yaitu kecepatan dan konsumsi memori yang sulit diprediksi. NumPy mengambil jalan lain: setiap elemen array memakai tipe berlebar tetap (fixed-width), misalnya selalu tepat 4 byte per elemen untuk int32. Dengan lebar yang seragam, NumPy dapat menghitung alamat memori tiap elemen dan menjalankan operasi dalam bahasa C secara massal.

Bab ini menelusuri empat keluarga tipe numerik NumPy:

  • Integer bertanda: int8, int16, int32, int64.
  • Integer tak bertanda (unsigned): uint8, uint16, uint32, uint64.
  • Floating point: float16, float32, float64.
  • Complex: complex64, complex128.

Keluarga Integer dan np.iinfo #

Nama tipe integer langsung menunjukkan lebarnya dalam bit: int16 berarti bilangan bulat 16 bit atau 2 byte per elemen. Karena lebarnya tetap, rentang nilai yang bisa ditampung juga tetap. Fungsi np.iinfo melaporkan batas bawah dan batas atas setiap tipe integer.

python
import numpy as np

for t in [np.int8, np.int16, np.int32, np.int64]:
    info = np.iinfo(t)
    print(f"{info.dtype}: {info.min} sampai {info.max}")

print("dtype default:", np.array([10, 20, 30]).dtype)

Output yang Dihasilkan:

text
int8: -128 sampai 127
int16: -32768 sampai 32767
int32: -2147483648 sampai 2147483647
int64: -9223372036854775808 sampai 9223372036854775807
dtype default: int64

Mari kita bedah blok di atas:

  1. Baris 3 (for t in [np.int8, ...]): loop ini mengambil objek tipe NumPy satu per satu, bukan string nama; np.int8 adalah kelas dtype yang bisa dipakai langsung.
  2. Baris 4 (np.iinfo(t)): fungsi ini mengembalikan objek iinfo berisi metadata rentang untuk tipe integer t.
  3. Baris 5 (f-string): atribut info.dtype memberi nama tipe, sedangkan info.min dan info.max memberi batas rentang.
  4. Baris 7 (np.array([10, 20, 30]).dtype): NumPy memilih int64 sebagai tipe bawaan untuk array integer yang dibuat tanpa perintah eksplisit.

Tabel berikut merangkum keluarga integer yang paling sering dipakai:

dtypeUkuranRentang nilai
int81 byte-128 sampai 127
int162 byte-32768 sampai 32767
int324 bytesekitar -2,1 miliar sampai 2,1 miliar
int648 bytesekitar -9,2 × 10^18 sampai 9,2 × 10^18
uint81 byte0 sampai 255
uint324 byte0 sampai sekitar 4,2 miliar

Integer Unsigned (uint) #

Tipe uint adalah integer tanpa tanda negatif. Bit yang biasa dipakai untuk menandai negatif dialihkan ke nilai positif, sehingga rentangnya bergeser ke atas: uint8 menampung 0 sampai 255, dua kali lipat batas atas int8. Tipe ini cocok untuk nilai yang mustahil negatif, misalnya intensitas piksel gambar (0-255) atau jumlah stok.

Satu catatan penting: operasi campuran antara uint dan integer negatif dapat menghasilkan nilai yang mengejutkan karena hasilnya kembali melingkar ke sisi positif. Jika data memang bisa negatif, pakai tipe int bertanda.

Overflow: Nilai Melampaui Batas #

Karena lebarnya tetap, integer NumPy tidak bisa tumbuh seperti int Python. Ketika hasil operasi melewati batas rentang, nilai dibungkus (wrap) ke sisi berlawanan seolah ada operasi modulo. Perilaku ini terjadi tanpa menghentikan program.

python
import numpy as np

a = np.int8(127)
b = a + np.int8(1)
print(b, b.dtype)

arr = np.array([126, 127], dtype=np.int8)
print(arr + np.int8(1))

Output yang Dihasilkan:

text
-128 int8
[ 127 -128]

Interpretasi hasilnya:

  1. Baris 3-4 (a + np.int8(1)): nilai 127 + 1 seharusnya 128, tetapi 128 berada di luar rentang int8, sehingga hasilnya dibungkus menjadi -128.
  2. Baris 7 (arr + np.int8(1)): pada array, elemen 127 dibungkus menjadi -128, sementara 126 masih aman menjadi 127.

Satu hal yang perlu kita ketahui: pada operasi scalar di NumPy 2.x, baris keempat juga memunculkan RuntimeWarning: overflow encountered in scalar add di stderr. Peringatan itu tidak menghentikan eksekusi dan tidak mengubah hasil; program tetap melanjutkan dengan nilai hasil bungkus. Operasi pada array, seperti baris ketujuh, berjalan tanpa peringatan sama sekali.

Keluarga Floating Point dan complex #

Tipe float NumPy mengikuti standar IEEE 754: float16 (2 byte), float32 (4 byte), dan float64 (8 byte). Semakin lebar, semakin banyak bit untuk mantissa sehingga presisi meningkat. Fungsi np.finfo melaporkan metadata tipe float, termasuk eps, yaitu jarak terkecil yang masih bisa dibedakan dari 1.0.

python
import numpy as np

print(np.float64(0.1) + np.float64(0.2))
print(np.float32(0.1) + np.float32(0.2))
print(np.float32(16777216) + np.float32(1))
print(np.array([1 + 2j, 3 - 1j]).dtype)

info32 = np.finfo(np.float32)
info64 = np.finfo(np.float64)
print("float32 eps:", info32.eps)
print("float64 eps:", info64.eps)

Output yang Dihasilkan:

text
0.30000000000000004
0.3
16777216.0
complex128
float32 eps: 1.1920929e-07
float64 eps: 2.220446049250313e-16

Baris demi baris:

  1. Baris 3: penjumlahan 0.1 + 0.2 pada float64 menghasilkan 0.30000000000000004. Ini bukan bug NumPy, melainkan sifat biner IEEE 754; 0.1 memang tidak bisa direpresentasikan persis dalam biner.
  2. Baris 4: pada float32, galat pembulatan yang sama berakhir terlihat sebagai 0.3 karena pembulatan float32 justru menyamarkan ekor kecil itu. Jangan salah paham: float32 lebih kasar, bukan lebih akurat.
  3. Baris 5: float32 hanya punya 24 bit mantissa; di atas 16777216 (2^24), penambahan 1 tidak lagi terwakili sehingga hasilnya kembali 16777216.0.
  4. Baris 6: array berisi bilangan complex otomatis memakai complex128, yaitu sepasang float64 untuk bagian real dan imajiner.
dtypeUkuranPresisi khas
float162 bytesekitar 3 angka desimal
float324 bytesekitar 7 angka desimal
float648 bytesekitar 15-16 angka desimal
complex12816 bytedua float64 (real + imajiner)

Untuk tipe complex, cukup ingat pola berikut: np.complex64 menyimpan real dan imajiner sebagai sepasang float32, sedangkan complex128 memakai sepasang float64. Kebutuhan nyata akan complex muncul pada pemrosesan sinyal dan transformasi Fourier, yang berada di luar cakupan bab ini.