Data sudah tersimpan rapi — vektor, matriks, dan bilangan complex dari chapter-chapter sebelumnya kini tinggal dihitung, dan di sinilah <cmath> masuk: satu header berisi seluruh fungsi matematika standar C++ mulai dari akar kuadrat, eksponensial, logaritma, sampai trigonometri. Header ini juga tempat tinggal aturan-aturan halus yang sering menggigit: sqrt dari bilangan negatif tidak melempar exception melainkan mengembalikan NaN yang diam-diam menular ke hasil akhir, fmod dan remainder memberi sisa pembagian yang berbeda arah untuk input negatif, dan static_cast<int> memotong ke arah nol alih-alih membulatkan. Chapter ini menurunkan semuanya ke satu program teruji, lalu menutup dengan resep konversi antar tipe angka yang memeriksa rentang sebelum mempersempit — bukan sesudah hasilnya tak masuk akal.

Peta Fungsi <cmath> #

KelompokFungsiCatatan pemakaian
Akar & pangkatsqrt, pow, cbrtsqrt(x) untuk x negatif → NaN; pow(2,10) = 1024
Eksponen & logexp, log (basis e), log10, log2log bilangan nonpositif → NaN atau -inf pada nol
Trigonometrisin, cos, tan, plus asin, atan2argumen dalam radian, bukan derajat
Nilai mutlakfabs (double), abs (integer, dari <cstdlib>)satu nama, dua dunia tipe
Sisa pembagianfmod, remainderberbeda arah pemotongan untuk input negatif
Pembulatanfloor, ceil, trunc, roundtrunc memotong ke nol; round ke terdekat (0,5 ke atas)

Semua fungsi utama bekerja di atas double; ada overload untuk float dan long double, serta varian s dan f (sinf, sqrtl) untuk pemanggilan eksplisit. Pemisahan abs/fabs adalah warisan C yang penting dihafal: memanggil std::abs pada double sebenarnya berfungsi karena overload modern, tetapi menyebut fabs membuat maksudnya tak bisa salah dibaca.

Program Teruji #

cpp
#include <cmath>
#include <iostream>
#include <limits>

int main() {
    // 1. Fungsi dasar dari <cmath>
    std::cout << "sqrt(2)      = " << std::sqrt(2.0) << "\n";
    std::cout << "pow(2,10)    = " << std::pow(2.0, 10.0) << "\n";
    std::cout << "exp(1)       = " << std::exp(1.0) << "\n";
    std::cout << "log(100)     = " << std::log(100.0) << "\n";
    std::cout << "log10(100)   = " << std::log10(100.0) << "\n";
    std::cout << "sin(pi/6)    = "
              << std::sin(std::acos(-1.0) / 6.0) << "\n";

    // 2. abs untuk integer, fabs untuk floating-point
    std::cout << "fabs(-2.5)   = " << std::fabs(-2.5) << "\n";
    std::cout << "abs(-7)      = " << std::abs(-7) << "\n";

    // 3. fmod vs remainder: dua arah "sisa pembagian" floating
    std::cout << "fmod(10,3.5)      = " << std::fmod(10.0, 3.5) << "\n";
    std::cout << "remainder(10,3.5) = " << std::remainder(10.0, 3.5) << "\n";
    std::cout << "fmod(-10,3.5)     = " << std::fmod(-10.0, 3.5) << "\n";
    std::cout << "remainder(-10,3.5)= " << std::remainder(-10.0, 3.5) << "\n";

    // 4. Nilai khusus: sqrt negatif menghasilkan NaN, deteksi dengan isnan
    double akarNegatif = std::sqrt(-1.0);
    std::cout << "sqrt(-1)          = " << akarNegatif << "\n";
    std::cout << "isnan(akar)       = "
              << std::boolalpha << std::isnan(akarNegatif) << "\n";

    // 5. Konversi: truncation vs pembulatan eksplisit
    double harga = 3.99;
    std::cout << "static_cast<int>(3.99)  = "
              << static_cast<int>(harga) << "\n";
    std::cout << "static_cast<int>(-3.99) = "
              << static_cast<int>(-harga) << "\n";
    std::cout << "round(3.5)              = " << std::round(3.5) << "\n";
    std::cout << "floor(-3.9)             = " << std::floor(-3.9) << "\n";
    std::cout << "ceil(3.1)               = " << std::ceil(3.1) << "\n";

    // 6. Cast aman: periksa rentang sebelum mempersempit tipe
    double besar = 3e9;
    bool aman = besar >= std::numeric_limits<int>::lowest()
             && besar <= std::numeric_limits<int>::max();
    std::cout << "3e9 muat di int?  = " << aman << "\n";

    return 0;
}

Output yang Dihasilkan:

text
sqrt(2)      = 1.41421
pow(2,10)    = 1024
exp(1)       = 2.71828
log(100)     = 4.60517
log10(100)   = 2
sin(pi/6)    = 0.5
fabs(-2.5)   = 2.5
abs(-7)      = 7
fmod(10,3.5)      = 3
remainder(10,3.5) = -0.5
fmod(-10,3.5)     = -3
remainder(-10,3.5)= 0.5
sqrt(-1)          = -nan
isnan(akar)       = true
static_cast<int>(3.99)  = 3
static_cast<int>(-3.99) = -3
round(3.5)              = 4
floor(-3.9)             = -4
ceil(3.1)               = 4
3e9 muat di int?  = false

Bedah baris-per-baris:

  1. Baris 7-13 (sqrt ... sin): enam fungsi dasar dengan hasil yang sesuai matematika — exp(1) ≈ 2,71828 (bilangan e), log(100) ≈ 4,60517 (basis e), dan sin(π/6) = 0,5. Sudut trigonometri dibangun dari std::acos(-1.0) sebagai nilai π; semua argumen dalam radian.
  2. Baris 16-17 (fabs(-2.5) ... abs(-7)): dua fungsi nilai mutlak untuk dua dunia tipe — fabs menerima double, abs menerima integer. Hasilnya 2,5 dan 7 seperti diharapkan.
  3. Baris 20-23 (fmod ... remainder): perbedaan keduanya baru terlihat pada input negatif. fmod(10, 3.5) = 3 memotong hasil bagi ke arah nol (10/3,5 = 2,857 → 2, sisa 3); remainder(10, 3.5) = -0.5 membulatkan hasil bagi ke terdekat (3, sisa -0,5). Untuk input positif keduanya sering sama; untuk negatif, fmod(-10, 3.5) mempertahankan tanda pembilang (-3) sedangkan remainder(-10, 3.5) mengambil jalur terdekat (0,5).
  4. Baris 26-29 (std::sqrt(-1.0) ... std::isnan(...)): akar dari bilangan negatif di ranah double menghasilkan NaN, tercetak -nan — tanda minus hiasan dari bit sign yang tidak bermakna, seperti dibedah di Chapter Floating Point Representation. Fungsi std::isnan adalah satu-satunya cara sah mendeteksinya, karena perbandingan biasa terhadap NaN selalu false.
  5. Baris 32-39 (harga = 3.99 ... static_cast ... round ... floor ... ceil): static_cast<int> memotong ke arah nol: 3.99 → 3 dan -3.99 → -3 — bukan pembulatan, melainkan pembuangan desimal. Bila pembulatan yang dimaksud, panggil fungsi eksplisitnya: round(3.5) = 4, floor(-3.9) = -4 (ke bawah), ceil(3.1) = 4 (ke atas).
  6. Baris 42-45 (double besar = 3e9; bool aman = ...): 3 miliar berada di luar rentang int (maksimum 2.147.483.647), dan cek terhadap lowest()/max() mendeteksinya sebelum cast dijalankan. Tanpa cek ini, konversi double berukuran besar ke integer adalah undefined behavior — bukan sekadar angka aneh.

Konversi Aman dalam Praktik #

Pola baris 42-45 bisa Anda jadikan fungsi kecil yang dipakai berulang: periksa nilai terhadap std::numeric_limits<Target>::lowest() dan max(), kembalikan bool atau std::optional<Target> bila lolos. Dua aturan pendamping: bila tujuan Anda pembulatan, panggil std::round dulu baru cast (dan ingat hasilnya masih bisa meluap); dan bila input datang dari teks, pertimbangkan std::from_chars yang mengembalikan error terstruktur — dibahas pada Section Error Handling. Konversi melebar (int ke double, float ke double) justru selalu aman untuk rentangnya; yang perlu diwaspadai hanya kehilangan presisi ketika int 64-bit berisi nilai lebih dari 2⁵³ dimasukkan ke double.

Seluruh peralatan numerik kini sudah lengkap: representasi tipe, presisi, galat penjumlahan, pustaka matematika, bahkan bilangan acak. Chapter terakhir section ini merangkai semuanya menjadi disiplin kerja — cara menguji akurasi hasil, memilih metode yang stabil, dan keputusan-keputusan desain yang menjaga perhitungan tetap bisa dipercaya.

Rujukan resmi untuk topik Chapter ini: fungsi matematika umum <cmath> dan std::isnan di cppreference.