Skip to content

Commit

Permalink
Merge pull request #1676 from sjrd/double-to-int
Browse files Browse the repository at this point in the history
Fix #1671: Fix {Float,Double}.toInt for large abs values.
  • Loading branch information
gzm0 committed May 22, 2015
2 parents a82cfe6 + 507ca1c commit 51f0917
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 9 deletions.
2 changes: 1 addition & 1 deletion ci/checksizes.sh
Expand Up @@ -34,7 +34,7 @@ REVERSI_OPT_GZ_SIZE=$(stat '-c%s' "$REVERSI_OPT.gz")

case $FULLVER in
2.10.2)
REVERSI_PREOPT_EXPECTEDSIZE=657000
REVERSI_PREOPT_EXPECTEDSIZE=658000
REVERSI_OPT_EXPECTEDSIZE=139000
REVERSI_PREOPT_GZ_EXPECTEDSIZE=87000
REVERSI_OPT_GZ_EXPECTEDSIZE=39000
Expand Down
8 changes: 6 additions & 2 deletions javalib/src/main/scala/java/util/Random.scala
Expand Up @@ -35,10 +35,14 @@ class Random(seed_in: Long) extends AnyRef with java.io.Serializable {
*/

@inline
def _24msbOf(x: Double): Int = (x / (1 << 24).toDouble).toInt
def rawToInt(x: Double): Int =
(x.asInstanceOf[js.Dynamic] | 0.asInstanceOf[js.Dynamic]).asInstanceOf[Int]

@inline
def _24lsbOf(x: Double): Int = x.toInt & ((1 << 24) - 1)
def _24msbOf(x: Double): Int = rawToInt(x / (1 << 24).toDouble)

@inline
def _24lsbOf(x: Double): Int = rawToInt(x) & ((1 << 24) - 1)

// seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)

Expand Down
13 changes: 8 additions & 5 deletions library/src/main/scala/scala/scalajs/runtime/Bits.scala
Expand Up @@ -78,7 +78,7 @@ object Bits {
* support because we avoid several fround operations.
*/
def numberHashCode(value: Double): Int = {
val iv = value.toInt
val iv = rawToInt(value)
if (iv == value && 1.0/value != Double.NegativeInfinity) iv
else doubleToLongBits(value).hashCode()
}
Expand Down Expand Up @@ -146,7 +146,7 @@ object Bits {
val ebits = 8
val fbits = 23
val (s, e, f) = encodeIEEE754(ebits, fbits, value)
(if (s) 0x80000000 else 0) | (e << fbits) | f.toInt
(if (s) 0x80000000 else 0) | (e << fbits) | rawToInt(f)
}

private def longBitsToDoublePolyfill(bits: Long): Double = {
Expand All @@ -168,9 +168,9 @@ object Bits {
val fbits = 52
val hifbits = fbits-32
val (s, e, f) = encodeIEEE754(ebits, fbits, value)
val hif = (f / 0x100000000L.toDouble).toInt
val hif = rawToInt(f / 0x100000000L.toDouble)
val hi = (if (s) 0x80000000 else 0) | (e << hifbits) | hif
val lo = f.toInt
val lo = rawToInt(f)
(hi.toLong << 32) | (lo.toLong & 0xffffffffL)
}

Expand Down Expand Up @@ -223,7 +223,7 @@ object Bits {
if (av >= pow(2, 1-bias)) {
val twoPowFbits = pow(2, fbits)

var e = min(floor(log(av) / LN2).toInt, 1023)
var e = min(rawToInt(floor(log(av) / LN2)), 1023)
var f = roundToEven(av / pow(2, e) * twoPowFbits)
if (f / twoPowFbits >= 2) {
e = e + 1
Expand All @@ -246,6 +246,9 @@ object Bits {
}
}

@inline private def rawToInt(x: Double): Int =
(x.asInstanceOf[js.Dynamic] | 0.asInstanceOf[js.Dynamic]).asInstanceOf[Int]

@inline private[runtime] def roundToEven(n: Double): Double = {
val w = Math.floor(n)
val f = n - w
Expand Down
@@ -0,0 +1,50 @@
/* __ *\
** ________ ___ / / ___ __ ____ Scala.js Test Suite **
** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
** /____/\___/_/ |_/____/_/ | |__/ /____/ **
** |/____/ **
\* */
package org.scalajs.testsuite.compiler

import org.scalajs.jasminetest.JasmineTest

object DoubleTest extends JasmineTest {

describe("Double") {

it("toInt") {
@inline
def test(x: Double, expected: Int): Unit =
expect(x.toInt).toEqual(expected)

// Specials
test(+0.0, 0)
test(-0.0, 0)
test(Double.PositiveInfinity, Int.MaxValue)
test(Double.NegativeInfinity, Int.MinValue)
test(Double.NaN, 0)

// Positive numbers
test(0.3, 0)
test(0.7, 0)
test(1.2, 1)
test(5e12, Int.MaxValue)
test(2147483646, 2147483646)
test(2147483646.999, 2147483646)
test(2147483512.546, 2147483512)
test(65.67, 65)

// Negative numbers
test(-0.3, 0)
test(-0.7, 0)
test(-1.2, -1)
test(-5e12, Int.MinValue)
test(-2147483647.9999, -2147483647)
test(-2147483565.123, -2147483565)
test(-65.67, -65)
}

}

}
Expand Up @@ -16,6 +16,41 @@ object FloatTest extends JasmineTest {
y.toFloat
}

describe("Float") {

it("toInt") {
@inline
def test(x: Float, expected: Int): Unit =
expect(x.toInt).toEqual(expected)

// Specials
test(+0.0f, 0)
test(-0.0f, 0)
test(Float.PositiveInfinity, Int.MaxValue)
test(Float.NegativeInfinity, Int.MinValue)
test(Float.NaN, 0)

// Positive numbers
test(0.3f, 0)
test(0.7f, 0)
test(1.2f, 1)
test(5e12f, Int.MaxValue)
test(2147483646f, 2147483647)
test(2147483500f, 2147483520)
test(65.67f, 65)

// Negative numbers
test(-0.3f, 0)
test(-0.7f, 0)
test(-1.2f, -1)
test(-5e12f, Int.MinValue)
test(-2147483646f, -2147483648)
test(-2147483500f, -2147483520)
test(-65.67f, -65)
}

}

when("strict-floats").
describe("Strict floats") {

Expand Down
4 changes: 4 additions & 0 deletions tools/scalajsenv.js
Expand Up @@ -425,6 +425,10 @@ ScalaJS.isInfinite = function(instance) {
return !ScalaJS.g["isFinite"](instance) && !ScalaJS.isNaN(instance);
};

ScalaJS.doubleToInt = function(x) {
return (x > 2147483647) ? (2147483647) : ((x < -2147483648) ? -2147483648 : (x | 0));
};

/** Instantiates a JS object with variadic arguments to the constructor. */
ScalaJS.newJSObjectWithVarargs = function(ctor, args) {
// This basically emulates the ECMAScript specification for 'new'.
Expand Down
Expand Up @@ -1459,7 +1459,7 @@ object JSDesugaring {
val newLhs = transformExpr(lhs)
(op: @switch) match {
case Boolean_! => js.UnaryOp(JSUnaryOp.!, newLhs)
case DoubleToInt => js.BinaryOp(JSBinaryOp.|, newLhs, js.IntLiteral(0))
case DoubleToInt => genCallHelper("doubleToInt", newLhs)

case LongToInt => genLongMethodApply(newLhs, LongImpl.toInt)
case LongToDouble => genLongMethodApply(newLhs, LongImpl.toDouble)
Expand Down Expand Up @@ -2038,6 +2038,7 @@ object JSDesugaring {
"numberDoubleValue",
"isNaN",
"isInfinite",
"doubleToInt",
"systemArraycopy",
"systemIdentityHashCode",
"byteArray2TypedArray",
Expand Down
4 changes: 4 additions & 0 deletions tools/strongmodeenv.js
Expand Up @@ -593,6 +593,10 @@ class $ {
return !$g["isFinite"](instance) && !$.isNaN(instance);
};

static doubleToInt(x) {
return (x > 2147483647) ? (2147483647) : ((x < -2147483648) ? -2147483648 : (x | 0));
};

static systemArraycopy(src, srcPos, dest, destPos, length) {
const srcu = src.u;
const destu = dest.u;
Expand Down

0 comments on commit 51f0917

Please sign in to comment.