Skip to content

Primitive operations on Long with Float argument have different semantics from Java #11253

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
densh opened this issue Nov 14, 2018 · 2 comments · Fixed by scala/scala#7435
Closed

Comments

@densh
Copy link

densh commented Nov 14, 2018

Scala's primitive binary operations on Long that take Float (e.g. (x: Long) % (y: Float)) as an argument erroneously perform an operation in double precision, instead of float precision. This is inconsistent wrt Java semantics.

Java code:

public class JavaTest {
    private static float a() {
        return java.lang.Float.intBitsToFloat(1079290514);
    }

    private static long b() {
        return 1412906027847L;
    }

    public static void main(String[] args) {
        float r1 = b() % a();
        System.out.println(r1);
        float r2 = (float) ((float) b()) % ((float) a());
        System.out.println(r2);
        float r3 = (float) ((double) b()) % ((double) a());
        System.out.println(r3);
    }
}

Java output:

# java JavaTest
1.164309
1.164309
2.3242621

Scala code:

object Test {
  def a(): Float =
    java.lang.Float.intBitsToFloat(1079290514)
  def b(): Long =
    1412906027847L
  def main(args: Array[String]): Unit = {
    val r1: Float = b() % a()
    println(r1)
    val r2: Float = (b().toFloat % a().toFloat).toFloat
    println(r2)
    val r3: Float = (b().toDouble % a().toDouble).toFloat
    println(r3)
  }
}

Scala output:

# scala Test
2.3242621
1.164309
2.3242621

Found by random test generation for Scala Native (http://github.com/densh/testgen).

@densh
Copy link
Author

densh commented Nov 14, 2018

Scala Native and Scala.js (according to @sjrd) have the expected semantics like Java but it differs from Scala on the JVM.

@densh densh changed the title Primitive operations on Long with Float argument has different semantics from Java Primitive operations on Long with Float argument have different semantics from Java Nov 14, 2018
@sjrd
Copy link
Member

sjrd commented Nov 14, 2018

The code to be blamed is at https://github.com/scala/scala/blob/051e7b61cb18b7ed9593f38a4bc73b69e8199775/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala#L311-L314. It should have an additional case for other == FLOAT in which case the result should be FLOAT. Note how the case right below for case FLOAT => will correctly return FLOAT when other == LONG. So right now maxValueType is not commutative 😱

densh added a commit to densh/scala-native that referenced this issue Nov 15, 2018
Scalac mistakingly uses Double precision when performing
primitive binary operations on Long that take a Float
argument. Once this bug is fixed upstream we can conditionally
enable the workaround only on affected versions.
densh added a commit to scala-native/scala-native that referenced this issue Nov 15, 2018
Scalac mistakingly uses Double precision when performing
primitive binary operations on Long that take a Float
argument. Once this bug is fixed upstream we can conditionally
enable the workaround only on affected versions.
ekrich pushed a commit to ekrich/scala-native that referenced this issue May 21, 2021
Scalac mistakingly uses Double precision when performing
primitive binary operations on Long that take a Float
argument. Once this bug is fixed upstream we can conditionally
enable the workaround only on affected versions.
frontend-provider added a commit to frontend-provider/scala-native that referenced this issue Sep 20, 2023
Scalac mistakingly uses Double precision when performing
primitive binary operations on Long that take a Float
argument. Once this bug is fixed upstream we can conditionally
enable the workaround only on affected versions.
backend-devloper pushed a commit to backend-devloper/scala-native that referenced this issue Nov 24, 2023
Scalac mistakingly uses Double precision when performing
primitive binary operations on Long that take a Float
argument. Once this bug is fixed upstream we can conditionally
enable the workaround only on affected versions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants