Walk through kotlin.math as the multiplatform alternative to java.lang.Math, including how it handles integer rounding, NaN, and division edge cases.
answer
- kotlin.math replaces java.lang.Math in common
- NaN is unordered: use isNaN(), not == NaN
- toInt() truncates & NaN.toInt()==0; roundToInt throws on NaN
- Int div truncates, /0 throws; float /0 = Infinity
- % keeps dividend sign; mod keeps divisor sign
basics
~20 skotlin.math gives you sqrt, sin, pow, abs, PI and so on for every platform, so commonMain doesn't need java.lang.Math. It follows IEEE-754: things like 0.0/0.0 give NaN, and there are safe rounding helpers like roundToInt.
solid answer
~40 s`kotlin.math` is the **common** math package, the multiplatform stand-in for `java.lang.Math`. It exposes trig (`sin`, `cos`, `tan`, `atan2`), `sqrt`/`cbrt`, `pow`, `ln`/`log10`/`log2`, `exp`, `abs`, `min`/`max`, `sign`, `floor`/`ceil`/`round`/`truncate`, `hypot`, and constants `PI`, `E`. Floating point follows IEEE-754: `0.0/0.0` and `sqrt(-1.0)` produce `Double.NaN`; `1.0/0.0` is `Double.POSITIVE_INFINITY`. NaN is unordered, so use `x.isNaN()` rather than `x == Double.NaN` (which is always false). Kotlin adds safe conversions absent from java.lang.Math: `roundToInt()`/`roundToLong()` (which throw on NaN/overflow instead of silently truncating), `Double.toInt()` truncates toward zero. **Integer division** of `Int`/`Long` truncates toward zero and `0` divisor throws `ArithmeticException`, while floating division never throws. `(-7).mod(3)` gives a non-negative result whereas `%` keeps the dividend's sign.
code
kotlin · 8 linesimport kotlin.math.roundToInt
fun safePercent(value: Double, total: Double): Int {
if (total == 0.0) return 0
val pct = value / total * 100
require(!pct.isNaN()) { "unexpected NaN" }
return pct.roundToInt() // fail-fast on NaN, unlike toInt()
}go deeper
Knows kotlin.math exists and can call sqrt/abs/PI from shared code.
Uses roundToInt vs toInt correctly and knows NaN/Infinity are produced, not thrown.
Explains IEEE-754 unordered NaN, % vs mod signs, and the collection-equality vs operator-equality nuance.
Audits numeric code for portability and correctness, choosing fail-fast conversions and consistent rounding policy across the codebase.
## kotlin.math: the portable math package Because `commonMain` cannot see `java.lang.Math`, Kotlin ships `kotlin.math`, available on all targets: - **Trig**: `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `atan2(y, x)`. - **Powers/roots**: `sqrt`, `cbrt`, `pow(exp)`, `hypot(x, y)`. - **Logs/exp**: `ln`, `log10`, `log2`, `log(x, base)`, `exp`. - **Rounding**: `floor`, `ceil`, `round` (half-to-even / banker's rounding for `round`), `truncate`. - **Misc**: `abs`, `min`, `max`, `sign`, constants `PI`, `E`. ## IEEE-754 behavior Floating-point math never throws; it produces special values: ```kotlin import kotlin.math.sqrt println(0.0 / 0.0) // NaN println(sqrt(-1.0)) // NaN println(1.0 / 0.0) // Infinity println(-1.0 / 0.0) // -Infinity ``` **NaN is unordered**: every comparison with NaN is false, including `NaN == NaN`. So test with `x.isNaN()`, `x.isInfinite()`, `x.isFinite()`. Note Kotlin's *structural* equality on boxed `Double?` and in collections treats `NaN == NaN` as true and `-0.0 != 0.0` (a deliberate total ordering for set/map keys), which differs from the IEEE `==` operator on primitives. ## Safe rounding/conversions Kotlin adds helpers java.lang.Math lacks: - `Double.roundToInt()` / `roundToLong()` — round half-up, but **throw** `IllegalArgumentException` on `NaN` and clamp/overflow rules apply; far safer than a silent truncation. - `Double.toInt()` — truncates toward zero, and `NaN.toInt()` yields `0` (a classic trap). ```kotlin val x = Double.NaN x.toInt() // 0 (silent!) // x.roundToInt() // throws IllegalArgumentException — fail-fast ``` ## Integer vs floating division - `Int`/`Long` division **truncates toward zero**; dividing by `0` throws `ArithmeticException`. - `%` (rem) follows the **dividend's sign**: `(-7) % 3 == -1`. - `mod` always returns a result with the **divisor's sign**: `(-7).mod(3) == 2`. Pick `mod` for wrap-around indexing. ## Why this matters in KMP Using `kotlin.math` keeps numeric code in `commonMain` and gives **identical IEEE-754 semantics across platforms** — a major reason shared simulation/finance code can live in common.
- Why is `x == Double.NaN` always false, and what should you write instead?IEEE-754 defines NaN as unequal to everything including itself; use x.isNaN().
- When would you choose mod over %?For wrap-around/index math with negatives — mod always returns a non-negative result for a positive divisor, while % keeps the dividend's sign.
- Does floating-point division ever throw in Kotlin?No — Double/Float division produces Infinity or NaN; only integer division by zero throws ArithmeticException.
kotlin.math is a universal power adapter for math — same calculations plug into every platform socket with identical results.
saying these in an interview costs you the question
- Checks for NaN with == Double.NaN
- Assumes Double division by zero throws
- Thinks toInt() rounds rather than truncates
- Confuses % and mod sign behavior
- Reaches for java.lang.Math in commonMain