Math

Math #

dart:math adalah library bawaan Dart untuk operasi matematika — konstanta seperti pi dan e, fungsi trigonometri, logaritma, akar kuadrat, nilai minimum/maksimum, serta pembangkit angka acak. Untuk operasi matematika yang lebih kompleks (matriks, statistik, bilangan kompleks), gunakan package math dari pub.dev. Artikel ini membahas seluruh dart:math secara mendalam beserta contoh penerapan nyata.

Import #

import 'dart:math';

// Semua fungsi dan konstanta tersedia langsung setelah import
print(pi);     // 3.141592653589793
print(e);      // 2.718281828459045
print(sqrt(2)); // 1.4142135623730951

Konstanta Matematika #

import 'dart:math';

// Konstanta dasar
print(pi);       // π = 3.141592653589793 — rasio keliling dan diameter lingkaran
print(e);        // e = 2.718281828459045 — basis logaritma natural
print(sqrt2);    // √2 = 1.4142135623730951 — akar kuadrat dari 2
print(sqrt1_2);  // 1/√2 = 0.7071067811865476 — akar kuadrat dari 1/2
print(ln2);      // ln(2) = 0.6931471805599453 — logaritma natural dari 2
print(ln10);     // ln(10) = 2.302585092994046 — logaritma natural dari 10
print(log2e);    // log₂(e) = 1.4426950408889634 — logaritma basis 2 dari e
print(log10e);   // log₁₀(e) = 0.4342944819032518 — logaritma basis 10 dari e

// Konstanta derived yang berguna (tidak tersedia langsung, hitung manual)
final dua_pi = 2 * pi;         // 2π — satu putaran penuh dalam radian
final pi_per_dua = pi / 2;     // π/2 — 90 derajat dalam radian
final pi_per_empat = pi / 4;   // π/4 — 45 derajat dalam radian
final phi = (1 + sqrt(5)) / 2; // φ ≈ 1.618... — golden ratio

Fungsi Dasar #

min dan max #

import 'dart:math';

// min — nilai terkecil dari dua angka
print(min(3, 7));           // 3
print(min(-5, -2));         // -5
print(min(3.14, 2.71));    // 2.71
print(min(double.infinity, 100.0)); // 100.0

// max — nilai terbesar dari dua angka
print(max(3, 7));           // 7
print(max(-5, -2));         // -2

// Clamp — batasi nilai dalam rentang (bukan dari dart:math tapi method num)
double nilai = 150.0;
print(nilai.clamp(0, 100));  // 100.0 — dibatasi maksimal 100
print((-5).clamp(0, 100));   // 0 — dibatasi minimal 0
print(75.clamp(0, 100));     // 75 — dalam rentang, tidak berubah

// Min/Max dari list — gunakan reduce atau collection
List<int> angka = [3, 1, 4, 1, 5, 9, 2, 6];
int minimum = angka.reduce(min); // 1
int maksimum = angka.reduce(max); // 9

// Atau dengan package collection
import 'package:collection/collection.dart';
print(angka.min); // 1
print(angka.max); // 9

pow — Pemangkatan #

import 'dart:math';

// pow(x, y) — x pangkat y, mengembalikan num
print(pow(2, 10));      // 1024 — 2^10
print(pow(2, -1));      // 0.5 — 2^(-1) = 1/2
print(pow(4, 0.5));     // 2.0 — √4 (akar kuadrat = pangkat 1/2)
print(pow(8, 1/3));     // 2.0 — ∛8 (akar kubik = pangkat 1/3)
print(pow(10, 3));      // 1000 — 10^3
print(pow(-2, 3));      // -8 — (-2)^3

// Untuk pangkat integer, operator ~/ atau toInt() setelah pow
int kekuatan2 = pow(2, 8).toInt(); // 256

sqrt — Akar Kuadrat #

import 'dart:math';

print(sqrt(4));    // 2.0
print(sqrt(2));    // 1.4142135623730951
print(sqrt(9));    // 3.0
print(sqrt(0));    // 0.0
print(sqrt(-1));   // NaN — akar kuadrat bilangan negatif

// Akar n-th menggunakan pow
double akarKubik(double x) => pow(x, 1/3).toDouble();
print(akarKubik(27)); // 3.0

// Jarak Euclidean antara dua titik
double jarak(double x1, double y1, double x2, double y2) {
  return sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2));
}
print(jarak(0, 0, 3, 4)); // 5.0 — segitiga 3-4-5

Trigonometri #

Semua fungsi trigonometri dart:math bekerja dalam radian, bukan derajat:

import 'dart:math';

// Konversi antara derajat dan radian
double toRadian(double derajat) => derajat * pi / 180;
double toDegree(double radian) => radian * 180 / pi;

print(toRadian(90));   // 1.5707963... (π/2)
print(toDegree(pi));   // 180.0

// Fungsi trigonometri dasar
// sin, cos, tan — semua menerima radian
print(sin(0));                    // 0.0
print(sin(pi / 2));               // 1.0 — sin(90°)
print(sin(pi));                   // 1.2246467991473532e-16 (≈ 0, floating point)
print(cos(0));                    // 1.0
print(cos(pi));                   // -1.0 — cos(180°)
print(cos(pi / 2));               // 6.123233995736766e-17 (≈ 0)
print(tan(pi / 4));               // 1.0 (≈ 1) — tan(45°)
print(tan(toRadian(45)));         // 0.9999999999999999 ≈ 1

// Fungsi invers (arc)
print(asin(1));    // π/2 = 1.5707... — arcsin(1) = 90°
print(acos(1));    // 0.0 — arccos(1) = 0°
print(atan(1));    // π/4 = 0.7853... — arctan(1) = 45°

// atan2 — sudut dari titik (y, x) — lebih aman dari atan(y/x)
print(atan2(1, 1));   // π/4 = 0.7853... — titik (1,1) = 45°
print(atan2(0, -1));  // π = 3.1415... — titik (-1,0) = 180°
print(atan2(-1, 0));  // -π/2 — titik (0,-1) = -90°

Aplikasi Trigonometri #

import 'dart:math';

// Hitung koordinat titik pada lingkaran
// x = r * cos(θ), y = r * sin(θ)
List<(double, double)> titikPadaLingkaran(double radius, int n) {
  return List.generate(n, (i) {
    final sudut = 2 * pi * i / n;
    return (radius * cos(sudut), radius * sin(sudut));
  });
}

// 6 titik pada lingkaran jari-jari 10 (hexagon)
final titik = titikPadaLingkaran(10, 6);
for (final (x, y) in titik) {
  print('(${x.toStringAsFixed(2)}, ${y.toStringAsFixed(2)})');
}

// Haversine formula — jarak antara dua koordinat GPS
double haversine(
  double lat1, double lon1,
  double lat2, double lon2,
) {
  const radiusBumi = 6371.0; // km
  final dLat = toRadian(lat2 - lat1);
  final dLon = toRadian(lon2 - lon1);

  final a = sin(dLat / 2) * sin(dLat / 2) +
      cos(toRadian(lat1)) * cos(toRadian(lat2)) *
      sin(dLon / 2) * sin(dLon / 2);

  final c = 2 * atan2(sqrt(a), sqrt(1 - a));
  return radiusBumi * c;
}

// Jarak Jakarta → Surabaya
double jarak = haversine(-6.2088, 106.8456, -7.2459, 112.7378);
print('Jarak: ${jarak.toStringAsFixed(0)} km'); // ~664 km

Logaritma dan Eksponensial #

import 'dart:math';

// log — logaritma natural (basis e)
print(log(1));      // 0.0 — ln(1) = 0
print(log(e));      // 1.0 — ln(e) = 1
print(log(e * e));  // 2.0 — ln(e²) = 2
print(log(10));     // 2.302585... — ln(10)

// Logaritma basis lain — gunakan change of base formula: log_b(x) = ln(x) / ln(b)
double logBasis(double x, double basis) => log(x) / log(basis);
double log2(double x) => log(x) / ln2;    // logaritma basis 2
double log10(double x) => log(x) / ln10;  // logaritma basis 10

print(log2(8));    // 3.0 — 2^3 = 8
print(log10(100)); // 2.0 — 10^2 = 100
print(logBasis(27, 3)); // 3.0 — 3^3 = 27

// Eksponensial — e^x
double exp(double x) => pow(e, x).toDouble();
// atau lebih akurat: tidak ada exp() di dart:math, gunakan pow(e, x)

print(pow(e, 0));   // 1.0 — e^0
print(pow(e, 1));   // 2.718281... — e^1 = e
print(pow(e, 2));   // 7.389056... — e^2

Random — Angka Acak #

import 'dart:math';

// Random standar — pseudo-random, tidak kriptografis
final random = Random();

// Bilangan bulat acak [0, max)
print(random.nextInt(10));    // 0 sampai 9
print(random.nextInt(100));   // 0 sampai 99

// Rentang [min, max]
int rentang(int min, int max) => min + random.nextInt(max - min + 1);
print(rentang(1, 6));  // simulasi dadu — 1 sampai 6

// Double acak [0.0, 1.0)
print(random.nextDouble()); // 0.0 sampai 0.9999...

// Double dalam rentang [min, max)
double doubleRentang(double min, double max) {
  return min + random.nextDouble() * (max - min);
}
print(doubleRentang(1.5, 2.5)); // antara 1.5 dan 2.5

// Boolean acak
print(random.nextBool()); // true atau false dengan probabilitas 50%

// Seed — untuk hasil yang reproducible (berguna untuk testing)
final seeded = Random(42);
print(seeded.nextInt(100)); // selalu sama untuk seed yang sama
print(seeded.nextInt(100)); // urutan selalu sama

Random.secure — Kriptografis #

import 'dart:math';

// Random.secure — menggunakan sumber entropy OS, cocok untuk kriptografi
final secureRandom = Random.secure();

// Generate token acak yang aman (untuk session ID, API key, dll.)
String generateToken(int panjang) {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  return List.generate(
    panjang,
    (_) => chars[secureRandom.nextInt(chars.length)],
  ).join();
}

print(generateToken(32)); // token 32 karakter acak yang aman

// Generate bytes acak (untuk salt, nonce, dll.)
List<int> generateSalt(int ukuran) {
  return List.generate(ukuran, (_) => secureRandom.nextInt(256));
}

final salt = generateSalt(16);
print(salt); // [45, 127, 23, ...] — 16 bytes acak

// UUID v4 sederhana menggunakan Random.secure
String generateUUID() {
  final bytes = List.generate(16, (_) => secureRandom.nextInt(256));
  bytes[6] = (bytes[6] & 0x0f) | 0x40; // versi 4
  bytes[8] = (bytes[8] & 0x3f) | 0x80; // varian RFC 4122
  final hex = bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join();
  return '${hex.substring(0,8)}-${hex.substring(8,12)}-'
      '${hex.substring(12,16)}-${hex.substring(16,20)}-${hex.substring(20)}';
}

print(generateUUID()); // contoh: '550e8400-e29b-41d4-a716-446655440000'
// ANTI-PATTERN: menggunakan Random() biasa untuk kebutuhan keamanan
final random = Random();
final sessionId = random.nextInt(1000000).toString(); // ✗ mudah diprediksi!

// BENAR: Random.secure() untuk token yang butuh keamanan
final secureRandom = Random.secure();
final sessionId = generateToken(32); // ✓ tidak bisa diprediksi

Presisi Floating-Point — Gotcha yang Perlu Diketahui #

import 'dart:math';

// Floating-point representation tidak sempurna
print(0.1 + 0.2);          // 0.30000000000000004 — bukan 0.3!
print(0.1 + 0.2 == 0.3);   // false!

// Nilai spesial double
print(double.infinity);           // Infinity
print(double.negativeInfinity);   // -Infinity
print(double.nan);                // NaN
print(double.maxFinite);          // 1.7976931348623157e+308
print(double.minPositive);        // 5e-324

// Cek nilai spesial
double nilai = 0 / 0;
print(nilai.isNaN);          // true
print(nilai.isInfinite);     // false
print(nilai.isFinite);       // false

double inf = 1 / 0;
print(inf.isInfinite);       // true
print(inf.isNaN);            // false

// Perbandingan yang benar untuk floating-point
bool kiraKiraSama(double a, double b, {double toleransi = 1e-9}) {
  return (a - b).abs() < toleransi;
}

print(kiraKiraSama(0.1 + 0.2, 0.3));     // true ✓
print(kiraKiraSama(sin(pi), 0.0));        // true ✓ (sin(π) bukan tepat 0)

// Pembulatan
print(3.7.round());     // 4 — pembulatan biasa
print(3.5.round());     // 4 — pembulatan ke atas untuk .5
print(3.7.ceil());      // 4 — pembulatan ke atas
print(3.2.ceil());      // 4 — pembulatan ke atas
print(3.7.floor());     // 3 — pembulatan ke bawah
print(3.7.truncate());  // 3 — potong desimal (arah nol)
print((-3.7).truncate()); // -3 — berbeda dari floor!

// Format desimal
double harga = 15750.5;
print(harga.toStringAsFixed(0));  // '15751'
print(harga.toStringAsFixed(2));  // '15750.50'
print(harga.toStringAsPrecision(4)); // '1.575e+4'

Aplikasi Praktis #

Statistik Dasar #

import 'dart:math';

class Statistik {
  static double rerata(List<num> data) {
    if (data.isEmpty) return 0;
    return data.reduce((a, b) => a + b) / data.length;
  }

  static double variansPopulasi(List<num> data) {
    final rata = rerata(data);
    return data.map((x) => pow(x - rata, 2)).reduce((a, b) => a + b) / data.length;
  }

  static double standarDeviasi(List<num> data) => sqrt(variansPopulasi(data));

  static num median(List<num> data) {
    if (data.isEmpty) throw ArgumentError('Data kosong');
    final sorted = List.of(data)..sort();
    final mid = sorted.length ~/ 2;
    return sorted.length.isOdd
        ? sorted[mid]
        : (sorted[mid - 1] + sorted[mid]) / 2;
  }

  static num modus(List<num> data) {
    final frekuensi = <num, int>{};
    for (final x in data) frekuensi[x] = (frekuensi[x] ?? 0) + 1;
    return frekuensi.entries.reduce((a, b) => a.value > b.value ? a : b).key;
  }
}

void main() {
  final data = [4, 8, 15, 16, 23, 42, 15, 8, 15];

  print('Rerata: ${Statistik.rerata(data).toStringAsFixed(2)}');
  print('Median: ${Statistik.median(data)}');
  print('Modus: ${Statistik.modus(data)}');
  print('Std Dev: ${Statistik.standarDeviasi(data).toStringAsFixed(2)}');
}

Operasi Bit dan Pangkat 2 #

import 'dart:math';

// Cek apakah angka adalah pangkat 2
bool adalahPangkat2(int n) => n > 0 && (n & (n - 1)) == 0;
// menggunakan bit manipulation — lebih efisien dari pow
print(adalahPangkat2(16)); // true
print(adalahPangkat2(12)); // false

// Bulatkan ke pangkat 2 terdekat
int bulatkanKePangkat2(int n) {
  if (adalahPangkat2(n)) return n;
  int hasil = 1;
  while (hasil < n) hasil <<= 1;
  return hasil;
}
print(bulatkanKePangkat2(100)); // 128

// Logaritma integer (floor log base 2)
int floorLog2(int n) {
  assert(n > 0);
  return (log(n) / ln2).floor();
}
print(floorLog2(8));   // 3 — 2^3 = 8
print(floorLog2(10));  // 3 — 2^3 = 8 ≤ 10 < 2^4 = 16

Referensi Lengkap dart:math #

Konstanta #

Konstanta Nilai Deskripsi
pi 3.14159… π
e 2.71828… Bilangan Euler
sqrt2 1.41421… √2
sqrt1_2 0.70710… 1/√2
ln2 0.69314… ln(2)
ln10 2.30258… ln(10)
log2e 1.44269… log₂(e)
log10e 0.43429… log₁₀(e)

Fungsi #

Fungsi Keterangan
min(a, b) Nilai minimum dari dua angka
max(a, b) Nilai maksimum dari dua angka
pow(x, y) x pangkat y
sqrt(x) Akar kuadrat
log(x) Logaritma natural
sin(x) Sinus (radian)
cos(x) Kosinus (radian)
tan(x) Tangen (radian)
asin(x) Arcus sinus
acos(x) Arcus kosinus
atan(x) Arcus tangen
atan2(y, x) Sudut dari vektor (y, x)

Kelas #

Kelas Keterangan
Random() Pseudo-random number generator
Random.secure() Kriptografis RNG menggunakan entropy OS
Point<T> Representasi titik 2D dengan metode distanceTo

Ringkasan #

  • dart:math menyediakan konstanta pi, e, sqrt2, ln2, ln10 — tidak perlu mendefinisikan ulang di kode kamu.
  • Semua fungsi trigonometri bekerja dalam radian — konversi dari/ke derajat dengan radian = derajat * pi / 180.
  • atan2(y, x) lebih aman dari atan(y/x) — menangani kasus pembagian nol dan mengembalikan sudut yang benar di semua kuadran.
  • log(x) adalah logaritma natural — untuk basis lain gunakan change of base: log(x) / log(basis) atau log(x) / ln2 untuk basis 2.
  • Random() untuk simulation, Random.secure() untuk keamanan — token, session ID, salt, dan nonce harus menggunakan Random.secure() yang tidak bisa diprediksi.
  • Floating-point tidak sempurna0.1 + 0.2 != 0.3. Gunakan fungsi perbandingan dengan toleransi (abs(a-b) < epsilon) untuk membandingkan nilai floating-point.
  • num.clamp(min, max) adalah method pada num, bukan fungsi di dart:math — berguna untuk membatasi nilai dalam rentang tertentu.
  • reduce(min) dan reduce(max) untuk mencari minimum/maksimum dari List — lebih idiomatis dari loop manual.
  • Random(seed) untuk hasil yang reproducible — berguna dalam test, simulasi, dan debugging yang butuh hasil deterministic.
  • Untuk matematika yang lebih kompleks (matriks, FFT, statistik lanjut, bilangan kompleks), gunakan package math atau ml_linalg dari pub.dev.

← Sebelumnya: IO   Berikutnya: Async →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact