Skip to content

Commit

Permalink
Implement Math.multiplyHigh for Long (#3480)
Browse files Browse the repository at this point in the history
* Created Math multiplyHigh method
* Move multiplyHigh tests to JDK9 tests dir
  • Loading branch information
jspenger committed Oct 4, 2023
1 parent 778cbc4 commit 6c89cde
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 0 deletions.
18 changes: 18 additions & 0 deletions javalib/src/main/scala/java/lang/Math.scala
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,24 @@ object Math {
else overflow.value
}

@alwaysinline def multiplyHigh(a: scala.Long, b: scala.Long): scala.Long = {
/* Algorithm from Hacker's Delight, "8–2. Multiply high signed."
* Here, `a` is replaced with `u`, and `b` with `v`, and reassignment of
* variables with suffix `p`. Unsigned ints correspond to shifting with
* `>>>` and performing the `& 0xffffffffL` operations.
*/
val u0 = a & 0xffffffffL
val u1 = a >> 32
val v0 = b & 0xffffffffL
val v1 = b >> 32
val w0 = u0 * v0
val t = u1 * v0 + (w0 >>> 32)
val w1 = t & 0xffffffffL
val w2 = t >> 32
val w1p = u0 * v1 + w1
u1 * v1 + w2 + (w1p >> 32)
}

@alwaysinline def multiplyExact(a: scala.Long, b: scala.Int): scala.Long =
multiplyExact(a, b.toLong)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,41 @@ class MathTestOnJDK9 {
assertEquals(10.0, Math.fma(2.0, 3.0, 4.0), 0.0)
}

@Test def multiplyHighTests(): Unit = {
case class MHTest(a: Long, b: Long, expected: Long)
val maxval = java.lang.Long.MAX_VALUE
val minval = java.lang.Long.MIN_VALUE
val halfmax = maxval >> 32
val halfmin = minval >> 32

val testcases: List[MHTest] =
MHTest(maxval, maxval, 4611686018427387903L) ::
MHTest(maxval, minval, -4611686018427387904L) ::
MHTest(minval, minval, 4611686018427387904L) ::
MHTest(maxval, 0L, 0L) ::
MHTest(minval, 0L, 0L) ::
MHTest(0L, 0L, 0L) ::
MHTest(maxval, halfmax, 1073741823L) ::
MHTest(maxval, halfmin, -1073741824L) ::
MHTest(halfmax, halfmin, -1L) ::
MHTest(halfmin, halfmin, 0L) ::
MHTest(halfmax, 127L, 0L) ::
MHTest(halfmax * 42L, halfmax * 1337L, 14038L) ::
MHTest(halfmin * 42L, halfmax * 1337L, -14039L) ::
MHTest(13L, 37L, 0L) ::
MHTest(123456789123456789L, 987654321L, 6609981L) ::
MHTest(123123456456789789L, 998877665544332211L, 6667044887047954L) ::
MHTest(-123123456456789789L, 998877665544332211L, -6667044887047955L) ::
MHTest(123123456456789789L, -998877665544332211L, -6667044887047955L) ::
MHTest(-123123456456789789L, -998877665544332211L, 6667044887047954L) ::
Nil

for (tc <- testcases) {
val result = Math.multiplyHigh(tc.a, tc.b)
assertTrue(
s"Math.multiplyHigh(${tc.a}, ${tc.b}) result: ${result} != expected: ${tc.expected}",
Math.multiplyHigh(tc.a, tc.b) == tc.expected
)
}
}
}

0 comments on commit 6c89cde

Please sign in to comment.