Use HALF_EVEN rounding mode for round()

Add docs and tests for rounding.

 #KT-4900
This commit is contained in:
Ilya Gorbunov
2017-07-21 19:19:55 +03:00
parent 5e9e6d5951
commit d0b12e3872
3 changed files with 213 additions and 10 deletions
+78 -5
View File
@@ -266,10 +266,52 @@ public inline fun log2(a: Double): Double = nativeMath.log2(a)
@InlineOnly
public inline fun log1p(a: Double): Double = nativeMath.log1p(a)
/**
* Rounds the given value [a] to an integer towards positive infinity.
inline fun ceil(a: Double): Double = nativeMath.ceil(a).unsafeCast<Double>() // TODO: Remove unsafe cast after removing public js.math
inline fun floor(a: Double): Double = nativeMath.floor(a).unsafeCast<Double>()
inline fun truncate(a: Double): Double = nativeMath.trunc(a) // polyfill
* @return the smallest double value that is greater than the given value [a] and is a mathematical integer.
*
* Special cases:
* - `ceil(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer.
*/
@InlineOnly
public inline fun ceil(a: Double): Double = nativeMath.ceil(a).unsafeCast<Double>() // TODO: Remove unsafe cast after removing public js.math
/**
* Rounds the given value [a] to an integer towards negative infinity.
* @return the largest double value that is smaller than the given value [a] and is a mathematical integer.
*
* Special cases:
* - `floor(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer.
*/
@InlineOnly
public inline fun floor(a: Double): Double = nativeMath.floor(a).unsafeCast<Double>()
/**
* Rounds the given value [a] to an integer towards zero.
*
* @return the value [a] having its fractional part truncated.
*
* Special cases:
* - `truncate(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer.
*/
@InlineOnly
public inline fun truncate(a: Double): Double = nativeMath.trunc(a)
/**
* Rounds the given value [a] towards the closest integer with ties rounded towards even integer.
*
* Special cases:
* - `round(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer.
*/
public fun round(a: Double): Double {
if (a % 0.5 != 0.0) {
return nativeMath.round(a).unsafeCast<Double>()
}
val floor = floor(a)
return if (floor % 2 == 0.0) floor else ceil(a)
}
// also as extension val [absoluteValue]
inline fun abs(a: Double): Double = nativeMath.abs(a)
@@ -302,8 +344,39 @@ inline val Double.sign: Double get() = nativeMath.sign(this)
fun Double.withSign(sign: Double): Double = this.absoluteValue * sign.sign
inline fun Double.withSign(sign: Int): Double = this.withSign(sign.toDouble())
/**
* Rounds this [Double] value to the nearest integer and converts the result to [Int].
* Ties are rounded towards positive infinity.
*
* Special cases:
* - `x.roundToInt() == Int.MAX_VALUE` when `x > Int.MAX_VALUE`
* - `x.roundToInt() == Int.MIN_VALUE` when `x < Int.MIN_VALUE`
*
* @throws IllegalArgumentException when this value is `NaN`
*/
public fun Double.roundToInt(): Int = when {
isNaN() -> throw IllegalArgumentException("Cannot round NaN value.")
this > Int.MAX_VALUE -> Int.MAX_VALUE
this < Int.MIN_VALUE -> Int.MIN_VALUE
else -> nativeMath.round(this).unsafeCast<Double>().toInt()
}
fun Double.roundToLong(): Long = if (isNaN()) throw IllegalArgumentException("Cannot round NaN value.") else nativeMath.round(this).unsafeCast<Double>().toLong()
/**
* Rounds this [Double] value to the nearest integer and converts the result to [Long].
* Ties are rounded towards positive infinity.
*
* Special cases:
* - `x.roundToLong() == Long.MAX_VALUE` when `x > Long.MAX_VALUE`
* - `x.roundToLong() == Long.MIN_VALUE` when `x < Long.MIN_VALUE`
*
* @throws IllegalArgumentException when this value is `NaN`
*/
public fun Double.roundToLong(): Long = when {
isNaN() -> throw IllegalArgumentException("Cannot round NaN value.")
this > Long.MAX_VALUE -> Long.MAX_VALUE
this < Long.MIN_VALUE -> Long.MIN_VALUE
else -> nativeMath.round(this).unsafeCast<Double>().toLong()
}
@@ -325,7 +398,7 @@ inline fun Float.withSign(sign: Float): Float = this.toDouble().withSign(sign.to
inline fun Float.withSign(sign: Int): Float = this.toDouble().withSign(sign.toDouble()).toFloat()
fun Float.roundToInt(): Int = if (isNaN()) throw IllegalArgumentException("Cannot round NaN value.") else nativeMath.round(this)
fun Float.roundToInt(): Int = toDouble().roundToInt()
fun Float.roundToLong(): Long = toDouble().roundToLong()