diff --git a/js/js.libraries/src/core/kotlin.math.kt b/js/js.libraries/src/core/kotlin.math.kt index 4953029e4d5..e4bb151b11b 100644 --- a/js/js.libraries/src/core/kotlin.math.kt +++ b/js/js.libraries/src/core/kotlin.math.kt @@ -821,21 +821,98 @@ public inline fun Float.roundToLong(): Long = toDouble().roundToLong() -// Int -// also as extension val [absoluteValue] -fun abs(a: Int): Int = if (a < 0) -a else a -inline fun min(a: Int, b: Int): Int = minOf(a, b) -inline fun max(a: Int, b: Int): Int = maxOf(a, b) +/** + * Returns the absolute value of the given value [a]. + * + * Special cases: + * - `abs(Int.MIN_VALUE)` is `Int.MIN_VALUE` due to an overflow + * + * @see absoluteValue extension property for [Int] + */ +// TODO: remove manual 'or' when KT-19290 is fixed +public fun abs(a: Int): Int = if (a < 0) (-a or 0) else a -inline val Int.absoluteValue: Int get() = abs(this) +/** + * Returns the smaller of two values. + */ +@InlineOnly +public inline fun min(a: Int, b: Int): Int = minOf(a, b) + +/** + * Returns the greater of two values. + */ +@InlineOnly +public inline fun max(a: Int, b: Int): Int = maxOf(a, b) + +/** + * Returns the absolute value of this value. + * + * Special cases: + * - `Int.MIN_VALUE.absoluteValue` is `Int.MIN_VALUE` due to an overflow + * + * @see abs function + */ +@InlineOnly +public inline val Int.absoluteValue: Int get() = abs(this) + +/** + * Returns the sign of this value: + * - `-1` if the value is negative, + * - `0` if the value is zero, + * - `1` if the value is positive + */ +public val Int.sign: Int get() = when { + this < 0 -> -1 + this > 0 -> 1 + else -> 0 +} -// Long -// also as extension val [absoluteValue] -fun abs(a: Long): Long = if (a < 0) -a else a -inline fun min(a: Long, b: Long): Long = minOf(a, b) -inline fun max(a: Long, b: Long): Long = maxOf(a, b) +/** + * Returns the absolute value of the given value [a]. + * + * Special cases: + * - `abs(Long.MIN_VALUE)` is `Long.MIN_VALUE` due to an overflow + * + * @see absoluteValue extension property for [Long] + */ +public fun abs(a: Long): Long = if (a < 0) -a else a + +/** + * Returns the smaller of two values. + */ +@InlineOnly +public inline fun min(a: Long, b: Long): Long = minOf(a, b) + +/** + * Returns the greater of two values. + */ +@InlineOnly +public inline fun max(a: Long, b: Long): Long = maxOf(a, b) + +/** + * Returns the absolute value of this value. + * + * Special cases: + * - `Long.MIN_VALUE.absoluteValue` is `Long.MIN_VALUE` due to an overflow + * + * @see abs function + */ +@InlineOnly +public inline val Long.absoluteValue: Long get() = abs(this) + +/** + * Returns the sign of this value: + * - `-1` if the value is negative, + * - `0` if the value is zero, + * - `1` if the value is positive + */ +public val Long.sign: Int get() = when { + this < 0 -> -1 + this > 0 -> 1 + else -> 0 +} + -inline val Long.absoluteValue: Long get() = abs(this) diff --git a/libraries/stdlib/src/kotlin/util/MathJVM.kt b/libraries/stdlib/src/kotlin/util/MathJVM.kt index 39ddc0fa02c..3bdc2f2b6be 100644 --- a/libraries/stdlib/src/kotlin/util/MathJVM.kt +++ b/libraries/stdlib/src/kotlin/util/MathJVM.kt @@ -915,21 +915,99 @@ public fun Float.roundToLong(): Long = toDouble().roundToLong() -// Int -// also as extension val [absoluteValue] +// ================== Integer math functions ===================================== + +/** + * Returns the absolute value of the given value [a]. + * + * Special cases: + * - `abs(Int.MIN_VALUE)` is `Int.MIN_VALUE` due to an overflow + * + * @see absoluteValue extension property for [Int] + */ +@InlineOnly public inline fun abs(a: Int): Int = nativeMath.abs(a) +/** + * Returns the smaller of two values. + */ +@InlineOnly public inline fun min(a: Int, b: Int): Int = nativeMath.min(a, b) + +/** + * Returns the greater of two values. + */ +@InlineOnly public inline fun max(a: Int, b: Int): Int = nativeMath.max(a, b) +/** + * Returns the absolute value of this value. + * + * Special cases: + * - `Int.MIN_VALUE.absoluteValue` is `Int.MIN_VALUE` due to an overflow + * + * @see abs function + */ +@InlineOnly public inline val Int.absoluteValue: Int get() = nativeMath.abs(this) +/** + * Returns the sign of this value: + * - `-1` if the value is negative, + * - `0` if the value is zero, + * - `1` if the value is positive + */ +public val Int.sign: Int get() = when { + this < 0 -> -1 + this > 0 -> 1 + else -> 0 +} -// Long -// also as extension val [absoluteValue] + + +/** + * Returns the absolute value of the given value [a]. + * + * Special cases: + * - `abs(Long.MIN_VALUE)` is `Long.MIN_VALUE` due to an overflow + * + * @see absoluteValue extension property for [Long] + */ +@InlineOnly public inline fun abs(a: Long): Long = nativeMath.abs(a) +/** + * Returns the smaller of two values. + */ +@InlineOnly public inline fun min(a: Long, b: Long): Long = nativeMath.min(a, b) + +/** + * Returns the greater of two values. + */ +@InlineOnly public inline fun max(a: Long, b: Long): Long = nativeMath.max(a, b) +/** + * Returns the absolute value of this value. + * + * Special cases: + * - `Long.MIN_VALUE.absoluteValue` is `Long.MIN_VALUE` due to an overflow + * + * @see abs function + */ +@InlineOnly public inline val Long.absoluteValue: Long get() = nativeMath.abs(this) + +/** + * Returns the sign of this value: + * - `-1` if the value is negative, + * - `0` if the value is zero, + * - `1` if the value is positive + */ +public val Long.sign: Int get() = when { + this < 0 -> -1 + this > 0 -> 1 + else -> 0 +} + diff --git a/libraries/stdlib/test/numbers/MathTest.kt b/libraries/stdlib/test/numbers/MathTest.kt index c75e4c45160..82fb88eced8 100644 --- a/libraries/stdlib/test/numbers/MathTest.kt +++ b/libraries/stdlib/test/numbers/MathTest.kt @@ -517,3 +517,32 @@ class FloatMathTest { } +class IntegerMathTest { + + @Test fun intSigns() { + val negatives = listOf(Int.MIN_VALUE, -65536, -1) + val positives = listOf(1, 100, 256, Int.MAX_VALUE) + negatives.forEach { assertEquals(-1, it.sign) } + positives.forEach { assertEquals(1, it.sign) } + assertEquals(0, 0.sign) + + (negatives - Int.MIN_VALUE).forEach { assertEquals(-it, it.absoluteValue) } + assertEquals(Int.MIN_VALUE, Int.MIN_VALUE.absoluteValue) + + positives.forEach { assertEquals(it, it.absoluteValue) } + } + + + @Test fun longSigns() { + val negatives = listOf(Long.MIN_VALUE, -65536L, -1L) + val positives = listOf(1L, 100L, 256L, Long.MAX_VALUE) + negatives.forEach { assertEquals(-1, it.sign) } + positives.forEach { assertEquals(1, it.sign) } + assertEquals(0, 0L.sign) + + (negatives - Long.MIN_VALUE).forEach { assertEquals(-it, it.absoluteValue) } + assertEquals(Long.MIN_VALUE, Long.MIN_VALUE.absoluteValue) + + positives.forEach { assertEquals(it, it.absoluteValue) } + } +} \ No newline at end of file