
Library enables exact base-10 arithmetic using native decimal types across platforms, providing consistent semantics and a single API for handling decimals, percentages, and currency amounts.
A tiny Kotlin Multiplatform library that provides a common abstraction over each platform’s native “true decimal” type:
Use it anywhere you need exact base‑10 arithmetic (money, percentages, rates) without floating‑point surprises, and keep one API across all targets.
Configured in this module’s Gradle build:
Kotlin version: 2.2.20
This library is not yet published to a public repository. Recommended ways to consume it today:
Example using an included build:
settings.gradle.kts in your app project:
includeBuild("../decimal") // path where this repo lives
Then in your module’s build.gradle.kts:
dependencies {
implementation(project(":decimal"))
}
Wasm JS target note: the library depends on npm package decimal.js 10.6.0; your build will fetch it automatically.
// Construct
val a = Decimal(42) // from Int
val b = Decimal(1234uL) // from ULong
val c = Decimal.fromString("12.50") // nullable
// Arithmetic (operators return Decimal)
val sum = a + Decimal.from(1)
val product = sum * Decimal.from(3)
// Division uses a general default (scale=10, HalfUp)
val quotient = product / Decimal.from(7)
// Explicit rounding
val rounded = quotient.rounded(scale = 2, rounding = Rounding.HalfEven)
// Move the decimal point
val dollars = Decimal(12345).movePointLeft(2) // 123.45
val cents = dollars.movePointRight(2) // 12345
// Sign helpers and truncation
val negative = dollars.inverted()
val truncated = dollars.truncate() // drop fractional part
// Conversions
val asULong = cents.toULong()
val asDouble = dollars.toDouble()Rounding defines the strategy used in explicit rounding operations:
APIs:
Note on division: the infix div operator (/) uses a general default of scale = 10 and rounding = HalfUp for convenience and cross‑platform consistency.
A small helper that expresses percentages as a Decimal where 1.00 is 100%.
val fivePercent = Percent.fromPercentagePoints(Decimal.from(5)) // 5% = 0.05
val tenPercent = Percent.Ten // 10% = 0.10
val hundred = Percent.OneHundred // 100% = 1.00
println(fivePercent.toIsoString()) // e.g. "5 %" (ISO 31-0 spacing)Constants:
A thin value class over Decimal for representing non‑negative currency amounts with two fractional digits. Construction coerces to two decimal places using Bankers’ rounding to reduce drift.
Key points:
Common APIs:
val amount = CurrencyAmount.fromString("12.345")!! // -> 12.35 (HalfEven)
val cents: ULong = amount.toCents() // 1235uL
val plusFee = amount + CurrencyAmount.fromDecimal(Decimal.from(1))
val discounted = amount * Percent.Ten // 10% of amount
// Multi‑step arithmetic without compounding rounding at each step
val result = amount.mapDecimal { d ->
((d * Decimal(3)) + Decimal(1)) / Decimal(2)
}
// Locale‑aware formatting (currently AU locale in this repo)
val s1 = amount.formatted(withSymbol = true) // e.g. "$12.35"
val s2 = amount.formatted(withSymbol = false) // e.g. "12.35"Additional helpers:
Platform notes:
Commands:
./gradlew build
This software is released under the LGPL License. See LICENSE.md for details.
A tiny Kotlin Multiplatform library that provides a common abstraction over each platform’s native “true decimal” type:
Use it anywhere you need exact base‑10 arithmetic (money, percentages, rates) without floating‑point surprises, and keep one API across all targets.
Configured in this module’s Gradle build:
Kotlin version: 2.2.20
This library is not yet published to a public repository. Recommended ways to consume it today:
Example using an included build:
settings.gradle.kts in your app project:
includeBuild("../decimal") // path where this repo lives
Then in your module’s build.gradle.kts:
dependencies {
implementation(project(":decimal"))
}
Wasm JS target note: the library depends on npm package decimal.js 10.6.0; your build will fetch it automatically.
// Construct
val a = Decimal(42) // from Int
val b = Decimal(1234uL) // from ULong
val c = Decimal.fromString("12.50") // nullable
// Arithmetic (operators return Decimal)
val sum = a + Decimal.from(1)
val product = sum * Decimal.from(3)
// Division uses a general default (scale=10, HalfUp)
val quotient = product / Decimal.from(7)
// Explicit rounding
val rounded = quotient.rounded(scale = 2, rounding = Rounding.HalfEven)
// Move the decimal point
val dollars = Decimal(12345).movePointLeft(2) // 123.45
val cents = dollars.movePointRight(2) // 12345
// Sign helpers and truncation
val negative = dollars.inverted()
val truncated = dollars.truncate() // drop fractional part
// Conversions
val asULong = cents.toULong()
val asDouble = dollars.toDouble()Rounding defines the strategy used in explicit rounding operations:
APIs:
Note on division: the infix div operator (/) uses a general default of scale = 10 and rounding = HalfUp for convenience and cross‑platform consistency.
A small helper that expresses percentages as a Decimal where 1.00 is 100%.
val fivePercent = Percent.fromPercentagePoints(Decimal.from(5)) // 5% = 0.05
val tenPercent = Percent.Ten // 10% = 0.10
val hundred = Percent.OneHundred // 100% = 1.00
println(fivePercent.toIsoString()) // e.g. "5 %" (ISO 31-0 spacing)Constants:
A thin value class over Decimal for representing non‑negative currency amounts with two fractional digits. Construction coerces to two decimal places using Bankers’ rounding to reduce drift.
Key points:
Common APIs:
val amount = CurrencyAmount.fromString("12.345")!! // -> 12.35 (HalfEven)
val cents: ULong = amount.toCents() // 1235uL
val plusFee = amount + CurrencyAmount.fromDecimal(Decimal.from(1))
val discounted = amount * Percent.Ten // 10% of amount
// Multi‑step arithmetic without compounding rounding at each step
val result = amount.mapDecimal { d ->
((d * Decimal(3)) + Decimal(1)) / Decimal(2)
}
// Locale‑aware formatting (currently AU locale in this repo)
val s1 = amount.formatted(withSymbol = true) // e.g. "$12.35"
val s2 = amount.formatted(withSymbol = false) // e.g. "12.35"Additional helpers:
Platform notes:
Commands:
./gradlew build
This software is released under the LGPL License. See LICENSE.md for details.