Math #

dart:math is Dart’s built-in library for mathematical operations — constants like pi and e, trigonometric functions, logarithms, square roots, minimum/maximum values, and random number generators. For more complex math (matrices, statistics, complex numbers), use the math package from pub.dev. This article covers all of dart:math in depth with real-world application examples.

Import #

import 'dart:math';

// All functions and constants are available right after importing
print(pi);     // 3.141592653589793
print(e);      // 2.718281828459045
print(sqrt(2)); // 1.4142135623730951

Mathematical Constants #

import 'dart:math';

// Basic constants
print(pi);       // π = 3.141592653589793 — the ratio of a circle's circumference to its diameter
print(e);        // e = 2.718281828459045 — the base of natural logarithms
print(sqrt2);    // √2 = 1.4142135623730951 — the square root of 2
print(sqrt1_2);  // 1/√2 = 0.7071067811865476 — the square root of 1/2
print(ln2);      // ln(2) = 0.6931471805599453 — the natural logarithm of 2
print(ln10);     // ln(10) = 2.302585092994046 — the natural logarithm of 10
print(log2e);    // log₂(e) = 1.4426950408889634 — the base-2 logarithm of e
print(log10e);   // log₁₀(e) = 0.4342944819032518 — the base-10 logarithm of e

// Useful derived constants (not available directly, compute manually)
final dua_pi = 2 * pi;         // 2π — one full revolution in radians
final pi_per_dua = pi / 2;     // π/2 — 90 degrees in radians
final pi_per_empat = pi / 4;   // π/4 — 45 degrees in radians
final phi = (1 + sqrt(5)) / 2; // φ ≈ 1.618... — the golden ratio

Basic Functions #

min and max #

import 'dart:math';

// min — the smallest of two numbers
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 — the largest of two numbers
print(max(3, 7));           // 7
print(max(-5, -2));         // -2

// Clamp — limit a value to a range (not from dart:math but a num method)
double nilai = 150.0;
print(nilai.clamp(0, 100));  // 100.0 — capped at 100
print((-5).clamp(0, 100));   // 0 — floored at 0
print(75.clamp(0, 100));     // 75 — within range, unchanged

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

// Or with the collection package
import 'package:collection/collection.dart';
print(angka.min); // 1
print(angka.max); // 9

pow — Exponentiation #

import 'dart:math';

// pow(x, y) — x to the power of y, returns a 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 (square root = power 1/2)
print(pow(8, 1/3));     // 2.0 — ∛8 (cube root = power 1/3)
print(pow(10, 3));      // 1000 — 10^3
print(pow(-2, 3));      // -8 — (-2)^3

// For integer powers, use ~/ or toInt() after pow
int kekuatan2 = pow(2, 8).toInt(); // 256

sqrt — Square Root #

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 — square root of a negative number

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

// Euclidean distance between two points
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 — a 3-4-5 triangle

Trigonometry #

All dart:math trigonometric functions work in radians, not degrees:

import 'dart:math';

// Conversion between degrees and radians
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

// Basic trigonometric functions
// sin, cos, tan — all accept radians
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

// Inverse functions (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 — the angle of a point (y, x) — safer than atan(y/x)
print(atan2(1, 1));   // π/4 = 0.7853... — point (1,1) = 45°
print(atan2(0, -1));  // π = 3.1415... — point (-1,0) = 180°
print(atan2(-1, 0));  // -π/2 — point (0,-1) = -90°

Trigonometry Applications #

import 'dart:math';

// Calculate point coordinates on a circle
// 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 points on a circle of radius 10 (hexagon)
final titik = titikPadaLingkaran(10, 6);
for (final (x, y) in titik) {
  print('(${x.toStringAsFixed(2)}, ${y.toStringAsFixed(2)})');
}

// The Haversine formula — distance between two GPS coordinates
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;
}

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

Logarithms and Exponentials #

import 'dart:math';

// log — natural logarithm (base 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)

// Logarithms in other bases — use the 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;    // base-2 logarithm
double log10(double x) => log(x) / ln10;  // base-10 logarithm

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

// Exponential — e^x
double exp(double x) => pow(e, x).toDouble();
// or more accurately: there's no exp() in dart:math, use 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 — Random Numbers #

import 'dart:math';

// Standard Random — pseudo-random, not cryptographic
final random = Random();

// Random integers [0, max)
print(random.nextInt(10));    // 0 to 9
print(random.nextInt(100));   // 0 to 99

// A range [min, max]
int rentang(int min, int max) => min + random.nextInt(max - min + 1);
print(rentang(1, 6));  // dice simulation — 1 to 6

// Random doubles [0.0, 1.0)
print(random.nextDouble()); // 0.0 to 0.9999...

// Doubles in a range [min, max)
double doubleRentang(double min, double max) {
  return min + random.nextDouble() * (max - min);
}
print(doubleRentang(1.5, 2.5)); // between 1.5 and 2.5

// Random booleans
print(random.nextBool()); // true or false with 50% probability

// Seed — for reproducible results (useful for testing)
final seeded = Random(42);
print(seeded.nextInt(100)); // always the same for the same seed
print(seeded.nextInt(100)); // the sequence is always the same

Random.secure — Cryptographic #

import 'dart:math';

// Random.secure — uses OS entropy sources, suitable for cryptography
final secureRandom = Random.secure();

// Generate a secure random token (for session IDs, API keys, etc.)
String generateToken(int panjang) {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  return List.generate(
    panjang,
    (_) => chars[secureRandom.nextInt(chars.length)],
  ).join();
}

print(generateToken(32)); // a secure 32-character random token

// Generate random bytes (for salts, nonces, etc.)
List<int> generateSalt(int ukuran) {
  return List.generate(ukuran, (_) => secureRandom.nextInt(256));
}

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

// A simple UUID v4 using Random.secure
String generateUUID() {
  final bytes = List.generate(16, (_) => secureRandom.nextInt(256));
  bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
  bytes[8] = (bytes[8] & 0x3f) | 0x80; // RFC 4122 variant
  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()); // example: '550e8400-e29b-41d4-a716-446655440000'
// ANTI-PATTERN: using plain Random() for security needs
final random = Random();
final sessionId = random.nextInt(1000000).toString(); // ✗ easily predictable!

// CORRECT: Random.secure() for tokens that need security
final secureRandom = Random.secure();
final sessionId = generateToken(32); // ✓ unpredictable

Floating-Point Precision — a Gotcha Worth Knowing #

import 'dart:math';

// Floating-point representation isn't perfect
print(0.1 + 0.2);          // 0.30000000000000004 — not 0.3!
print(0.1 + 0.2 == 0.3);   // false!

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

// Check special values
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

// Correct comparison for 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(π) isn't exactly 0)

// Rounding
print(3.7.round());     // 4 — standard rounding
print(3.5.round());     // 4 — rounds up for .5
print(3.7.ceil());      // 4 — rounds up
print(3.2.ceil());      // 4 — rounds up
print(3.7.floor());     // 3 — rounds down
print(3.7.truncate());  // 3 — truncates decimals (toward zero)
print((-3.7).truncate()); // -3 — different from floor!

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

Practical Applications #

Basic Statistics #

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('Empty data');
    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('Mean: ${Statistik.rerata(data).toStringAsFixed(2)}');
  print('Median: ${Statistik.median(data)}');
  print('Mode: ${Statistik.modus(data)}');
  print('Std Dev: ${Statistik.standarDeviasi(data).toStringAsFixed(2)}');
}

Bit Operations and Powers of Two #

import 'dart:math';

// Check whether a number is a power of 2
bool adalahPangkat2(int n) => n > 0 && (n & (n - 1)) == 0;
// uses bit manipulation — more efficient than pow
print(adalahPangkat2(16)); // true
print(adalahPangkat2(12)); // false

// Round up to the nearest power of 2
int bulatkanKePangkat2(int n) {
  if (adalahPangkat2(n)) return n;
  int hasil = 1;
  while (hasil < n) hasil <<= 1;
  return hasil;
}
print(bulatkanKePangkat2(100)); // 128

// Integer logarithm (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

Complete dart:math Reference #

Constants #

ConstantValueDescription
pi3.14159…π
e2.71828…Euler’s number
sqrt21.41421…√2
sqrt1_20.70710…1/√2
ln20.69314…ln(2)
ln102.30258…ln(10)
log2e1.44269…log₂(e)
log10e0.43429…log₁₀(e)

Functions #

FunctionDescription
min(a, b)The minimum of two numbers
max(a, b)The maximum of two numbers
pow(x, y)x to the power of y
sqrt(x)Square root
log(x)Natural logarithm
sin(x)Sine (radians)
cos(x)Cosine (radians)
tan(x)Tangent (radians)
asin(x)Arcsine
acos(x)Arccosine
atan(x)Arctangent
atan2(y, x)The angle of a vector (y, x)

Classes #

ClassDescription
Random()Pseudo-random number generator
Random.secure()Cryptographic RNG using OS entropy
Point<T>A 2D point representation with a distanceTo method

Summary #

  • dart:math provides the constants pi, e, sqrt2, ln2, ln10 — no need to redefine them in your code.
  • All trigonometric functions work in radians — convert from/to degrees with radian = derajat * pi / 180.
  • atan2(y, x) is safer than atan(y/x) — it handles division-by-zero cases and returns the correct angle in all quadrants.
  • log(x) is the natural logarithm — for other bases use the change of base: log(x) / log(basis) or log(x) / ln2 for base 2.
  • Random() for simulations, Random.secure() for security — tokens, session IDs, salts, and nonces must use the unpredictable Random.secure().
  • Floating-point isn’t perfect0.1 + 0.2 != 0.3. Use a tolerance-based comparison function (abs(a-b) < epsilon) to compare floating-point values.
  • num.clamp(min, max) is a method on num, not a dart:math function — useful for limiting values to a range.
  • reduce(min) and reduce(max) for finding the minimum/maximum of a List — more idiomatic than manual loops.
  • Random(seed) for reproducible results — useful in tests, simulations, and debugging that need deterministic outcomes.
  • For more complex math (matrices, FFT, advanced statistics, complex numbers), use the math or ml_linalg package from pub.dev.

← Previous: IO   Next: Async →

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