Perhitungan nyata jarang beruntung pada satu tipe data: array stok int32 harus dijumlahkan dengan hasil perhitungan diskon float32, data sensor integer bertemu rata-rata float64, dan hasilnya wajib punya satu dtype yang dipilih NumPy. Proses pemilihan itu mengikuti aturan promosi tipe (type promotion) — kaidah yang menentukan dtype hasil dari operasi antar tipe berbeda. Tanpa memahami kaidahnya, kita hanya bisa menebak mengapa hasil int32 + float32 ternyata float64, bukan float32.
Bab ini membahas empat alat pemeriksa tipe dari NumPy 2.x:
np.result_typedannp.promote_typesuntuk memprediksi dtype hasil;np.can_castuntuk memeriksa kebolehan konversi dengan modecasting;np.common_typeuntuk mencari tipe floating bersama;- aturan NEP 50 tentang scalar Python yang tidak lagi menaikkan dtype array.
Konsep dasarnya melengkapi praktik konversi manual pada Chapter Konversi Tipe Data dan strategi pemilihan tipe pada Memilih Tipe Data yang Tepat.
result_type: memprediksi dtype tanpa menghitung #
np.result_type menerima array, dtype, atau scalar Python, lalu mengembalikan dtype yang akan dipilih NumPy bila semuanya dipromosikan bersama. Fungsi ini tidak menjalankan operasi apa pun — hanya membaca kaidah — sehingga aman dipakai sebelum array besar dibuat:
import numpy as np
kombinasi = [
(np.int16, np.int32),
(np.int64, np.float64),
(np.float32, np.float64),
(np.int32, np.bool_),
]
for t1, t2 in kombinasi:
print(f"{t1.__name__} + {t2.__name__} -> {np.result_type(t1, t2).name}")Output yang Dihasilkan:
int16 + int32 -> int32
int64 + float64 -> float64
float32 + float64 -> float64
int32 + bool -> int32Hasilnya dirangkum dalam tabel kaidah berikut:
| Kombinasi | Hasil | Kaidah yang bekerja |
|---|---|---|
int16 + int32 | int32 | integer dengan kapasitas lebih besar menang |
int64 + float64 | float64 | floating selalu menang atas integer |
float32 + float64 | float64 | presisi lebih tinggi menang |
int32 + bool | int32 | bool diperlakukan sebagai 0/1, integer menang |
- Baris 3-8 (list dan loop): setiap pasangan dtype dikirim ke
np.result_type, dan.namemenghasilkan nama dtype untuk dicetak rapi. - Baris 9 (
print(...)): barisint32 + bool -> int32menunjukkan bahwabooladalah anggota keluarga integer terkecil; operasinilai + Truetetap dihitung dalam tipe integer lawannya.
promote_types dan can_cast #
np.promote_types adalah np.result_type untuk sepasang dtype saja, sedangkan np.can_cast menjawab pertanyaan berbeda: bolehkah tipe A dikonversi ke tipe B? Parameter casting mengatur standar kebolehannya — casting="safe" berarti konversi tidak akan mengubah nilai, sedangkan casting="unsafe" mengizinkan konversi meski presisi atau rentang nilainya terpotong.
import numpy as np
print(np.can_cast(np.int64, np.float64, casting="safe"))
print(np.can_cast(np.float64, np.int64, casting="safe"))
print(np.can_cast(np.float64, np.int64, casting="unsafe"))
print(np.promote_types(np.float32, np.float64))Output yang Dihasilkan:
True
False
True
float64- Baris 3 (
int64→float64): NumPy menilai konversi ini safe karena rentangfloat64mencakupint64. Perlu diingat: presisiint64di atas 2⁵³ tetap dapat berkurang, topik yang dibedah pada Chapter Penanganan Overflow dan Presisi. - Baris 4 (
float64→int64): pemeriksaan safe menolak, karena bagian desimal pasti hilang. - Baris 5 (
casting="unsafe"): pemeriksaan kini mengembalikanTrue. Mode unsafe hanya melonggarkan pemeriksaan — keputusan memotong nilai ada di tangan kita, persis seperti perilaku defaultastype. - Baris 6 (
np.promote_types): pasanganfloat32danfloat64dipromosikan kefloat64.
common_type: tipe floating bersama #
np.common_type menerima beberapa array dan mengembalikan tipe floating (atau complex) paling rendah yang mampu menampung semuanya. Seluruh masukan integer otomatis diangkat minimal ke float64:
import numpy as np
a = np.array([1, 2, 3], dtype=np.int32)
b = np.array([0.5, 1.5, 2.5], dtype=np.float32)
print(np.result_type(a, b))
print(np.common_type(a, b).__name__)
print((a + b).dtype)Output yang Dihasilkan:
float64
float64
float64- Baris 4 (
np.result_type(a, b)): arrayint32bertemu arrayfloat32— hasilnyafloat64, bukanfloat32. Alasannya: mantissafloat32hanya 24 bit, tidak cukup menampung semua bilanganint32secara utuh. - Baris 5 (
np.common_type(a, b).__name__):common_typemengembalikan class dtype (misalnyanumpy.float64), sehingga kita cetak lewat.nameagar outputnya bersih. Ingat juga: argumennya harus array atau scalar, bukan dtype. - Baris 6 (
(a + b).dtype): hasil operasi nyata cocok dengan prediksi —float64.
NEP 50: scalar Python tidak menaikkan dtype array #
Kaidah terpenting NumPy 2.x bernama NEP 50. Intinya sederhana: scalar Python (int, float, complex) berstatus weak — lemah — sehingga tidak ikut menentukan dtype hasil selama nilainya muat di dtype array. Jika nilainya tidak muat, NumPy menolak dengan error, bukan diam-diam menaikkan dtype. Perilaku lama NumPy 1.x yang menyesuaikan dtype dengan mempertimbangkan nilai scalar sudah ditinggalkan; perbandingan lengkapnya ada pada Chapter Migrasi NumPy 1.x ke 2.x.
import numpy as np
stok = np.array([100, 250, 400], dtype=np.int32)
print((stok + 5).dtype)
try:
print(stok + 10**12)
except OverflowError as e:
print("OverflowError:", e)
print((stok + 2.5).dtype)
print(stok + 1e100)Output yang Dihasilkan:
int32
OverflowError: Python integer 1000000000000 out of bounds for int32
float64
[1.e+100 1.e+100 1.e+100]- Baris 4 (
(stok + 5).dtype): scalar5muat diint32, maka dtype tetapint32— bukti bahwa scalar Python tidak menaikkan dtype array. - Baris 5-8 (try/except):
10**12melampaui batasint32(±2,1 miliar). NumPy 2.x memunculkanOverflowErroralih-alih mengubah dtype menjadiint64secara diam-diam. - Baris 9 (
(stok + 2.5).dtype): scalar2.5bertipe float memicu kaidah integer + float, sehingga hasilnyafloat64. - Baris 10 (
stok + 1e100):1e100besar tetapi muat difloat64, jadi tidak ada error; nilai array100,250,400menjadi tak berpengaruh setelah dijumlahkan ke1e100, sehingga cetakannya1.e+100semua.
Tabel berikut merangkum perilaku scalar Python pada NumPy 2.x untuk array int32:
| Ekspresi | Hasil | Penjelasan |
|---|---|---|
stok + 5 | int32 | scalar lemah; nilai muat |
stok + 10**12 | OverflowError | nilai di luar batas int32 |
stok + 2.5 | float64 | kaidah integer + float |
stok + 1e100 | float64 | nilai besar muat di float64 |
Prinsip yang sama berlaku pada array float: float32 dijumlahkan dengan 0.5 tetap float32, karena scalar float Python tidak menuntut kenaikan ke float64.
Aturan promosi yang kita kuasai di sini adalah sisi teori dari konversi eksplisit astype pada Chapter Konversi Tipe Data, dan menjadi dasar pertimbangan ketika memilih dtype hemat memori pada Memilih Tipe Data yang Tepat. Untuk dampak batas nilai dan presisi terhadap hasil hitung — termasuk kasus int64 ke float64 di atas — lanjutkan ke Penanganan Overflow dan Presisi.