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.
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:
int8: -128 sampai 127
int16: -32768 sampai 32767
int32: -2147483648 sampai 2147483647
int64: -9223372036854775808 sampai 9223372036854775807
dtype default: int64Mari kita bedah blok di atas:
- Baris 3 (
for t in [np.int8, ...]): loop ini mengambil objek tipe NumPy satu per satu, bukan string nama;np.int8adalah kelas dtype yang bisa dipakai langsung. - Baris 4 (
np.iinfo(t)): fungsi ini mengembalikan objekiinfoberisi metadata rentang untuk tipe integert. - Baris 5 (f-string): atribut
info.dtypememberi nama tipe, sedangkaninfo.mindaninfo.maxmemberi batas rentang. - Baris 7 (
np.array([10, 20, 30]).dtype): NumPy memilihint64sebagai tipe bawaan untuk array integer yang dibuat tanpa perintah eksplisit.
Tabel berikut merangkum keluarga integer yang paling sering dipakai:
| dtype | Ukuran | Rentang nilai |
|---|---|---|
| int8 | 1 byte | -128 sampai 127 |
| int16 | 2 byte | -32768 sampai 32767 |
| int32 | 4 byte | sekitar -2,1 miliar sampai 2,1 miliar |
| int64 | 8 byte | sekitar -9,2 × 10^18 sampai 9,2 × 10^18 |
| uint8 | 1 byte | 0 sampai 255 |
| uint32 | 4 byte | 0 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.
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:
-128 int8
[ 127 -128]Interpretasi hasilnya:
- Baris 3-4 (
a + np.int8(1)): nilai127 + 1seharusnya 128, tetapi 128 berada di luar rentangint8, sehingga hasilnya dibungkus menjadi-128. - Baris 7 (
arr + np.int8(1)): pada array, elemen127dibungkus menjadi-128, sementara126masih aman menjadi127.
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.
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:
0.30000000000000004
0.3
16777216.0
complex128
float32 eps: 1.1920929e-07
float64 eps: 2.220446049250313e-16Baris demi baris:
- Baris 3: penjumlahan
0.1 + 0.2padafloat64menghasilkan0.30000000000000004. Ini bukan bug NumPy, melainkan sifat biner IEEE 754;0.1memang tidak bisa direpresentasikan persis dalam biner. - Baris 4: pada
float32, galat pembulatan yang sama berakhir terlihat sebagai0.3karena pembulatan float32 justru menyamarkan ekor kecil itu. Jangan salah paham:float32lebih kasar, bukan lebih akurat. - Baris 5:
float32hanya punya 24 bit mantissa; di atas 16777216 (2^24), penambahan 1 tidak lagi terwakili sehingga hasilnya kembali16777216.0. - Baris 6: array berisi bilangan complex otomatis memakai
complex128, yaitu sepasangfloat64untuk bagian real dan imajiner.
| dtype | Ukuran | Presisi khas |
|---|---|---|
| float16 | 2 byte | sekitar 3 angka desimal |
| float32 | 4 byte | sekitar 7 angka desimal |
| float64 | 8 byte | sekitar 15-16 angka desimal |
| complex128 | 16 byte | dua 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.