From 480d4a0093514fea0d178aacf10d52dce848f9d4 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Thu, 31 Aug 2017 20:07:57 +0300 Subject: [PATCH] Make withSign(NaN) behave as in JVM #KT-4900 Where only the sign of the result is undefined, but the absolute value is unchanged. --- js/js.libraries/src/core/math.kt | 10 +++++----- js/js.libraries/src/js/misc.js | 6 ++++++ libraries/stdlib/test/numbers/MathTest.kt | 5 ++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/js/js.libraries/src/core/math.kt b/js/js.libraries/src/core/math.kt index fdae25b2311..ef4f97213ae 100644 --- a/js/js.libraries/src/core/math.kt +++ b/js/js.libraries/src/core/math.kt @@ -463,11 +463,11 @@ public inline val Double.sign: Double get() = nativeMath.sign(this) * If [sign] is `NaN` the sign of the result is undefined. */ @SinceKotlin("1.2") -public fun Double.withSign(sign: Double): Double = - this.absoluteValue * when(sign) { - 0.0 -> sign(1 / sign) - else -> sign(sign) - } +public fun Double.withSign(sign: Double): Double { + val thisSignBit = js("Kotlin").doubleSignBit(this).unsafeCast() + val newSignBit = js("Kotlin").doubleSignBit(sign).unsafeCast() + return if (thisSignBit == newSignBit) this else -this +} /** * Returns this value with the sign bit same as of the [sign] value. diff --git a/js/js.libraries/src/js/misc.js b/js/js.libraries/src/js/misc.js index 846946783e3..c610280ea1b 100644 --- a/js/js.libraries/src/js/misc.js +++ b/js/js.libraries/src/js/misc.js @@ -83,6 +83,12 @@ function imul(a, b) { bufInt32[0] = value; return bufFloat32[0]; }; + + // returns zero value for number with positive sign bit and non-zero value for number with negative sign bit. + Kotlin.doubleSignBit = function(value) { + bufFloat64[0] = value; + return bufInt32[1] & 0x80000000; + } })(); diff --git a/libraries/stdlib/test/numbers/MathTest.kt b/libraries/stdlib/test/numbers/MathTest.kt index 744c1ef89cc..8db44e364a1 100644 --- a/libraries/stdlib/test/numbers/MathTest.kt +++ b/libraries/stdlib/test/numbers/MathTest.kt @@ -301,7 +301,7 @@ class DoubleMathTest { for (b in allValues) { val r = a.withSign(b) assertEquals(a.absoluteValue, r.absoluteValue) - assertEquals(b.sign, r.sign) + assertEquals(b.sign, r.sign, "expected $a with sign bit of $b to have sign ${b.sign}") } val rp0 = a.withSign(0.0) @@ -315,6 +315,9 @@ class DoubleMathTest { val ri = a.withSign(-1) assertEquals(-1.0, ri.sign) assertEquals(a.absoluteValue, ri.absoluteValue) + + val rn = a.withSign(Double.NaN) + assertEquals(a.absoluteValue, rn.absoluteValue) } }