Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4734742

REGRESSION: Floating-point code works incorrectly with Server VM

    Details

    • Subcomponent:
    • Resolved In Build:
      fcs
    • CPU:
      x86
    • OS:
      windows_nt
    • Verification:
      Verified

      Backports

        Description

         

        Name: rmT116609 Date: 08/21/2002


        FULL PRODUCT VERSION :
        java version "1.4.1-rc"
        Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-rc-b19)
        Java HotSpot(TM) Server VM (build 1.4.1-rc-b19, mixed mode)

        FULL OPERATING SYSTEM VERSION :

        Windows NT Version 4.0 SP 6a

        A DESCRIPTION OF THE PROBLEM :

        In a modular multiplication algorithm the server VM works incorrectly. The algorithm involves mixed float, double and int type operands.

        I guess the problem involves some optimization that the C2 compiler makes. It's difficult to say exactly where it goes wrong.

        In the provided example code the result from calling only the modMultiply() method is always correct, and only the result involving modPow() is wrong. On the other hand, various workarounds only modifying the modMultiply() code
        will cause both results to become correct.

        The problem doesn't occur with the client VM or in interpreted mode. Also this particular case does work with J2SDK 1.4.0_01.

        The problem doesn't occur on SPARC Solaris but only on Windows x86 machines.

        The code in question is extremely performance critical, so any attempts to work around the problem by modifying the algorithm will make it slower, which is just unacceptable.


        REGRESSION. Last worked in version 1.4

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        1. Compile the provided source code.
        2. Run (many times): java -server FloatBugTest
        3. Observe the calculated values it prints out.


        EXPECTED VERSUS ACTUAL BEHAVIOR :
        Expected result: the printout should be

        8.2643241E9
        1000.0

        Actual result: the second sum is incorrect

        8.2643241E9
        5.6722724E9

        Depending on the computer you use, the incorrect result may not appear on the first run(s). E.g. if I boot the computer and don't run ANY Java programs before running FloatBugTest, the first run may produce the correct result.
        Only subsequent runs of java -server FloatBugTest produce the wrong result.

        You can also try to force compile e.g. run:
        java -Xcomp -server FloatBugTest

        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        import java.util.Random;

        public class FloatBugTest
        {
            private float modulus;
            private double inverseModulus;

            public final void setModulus(float modulus)
            {
                this.inverseModulus = 1.0 / (double) modulus;
                this.modulus = modulus;
            }

            public float modMultiply(float a, float b)
            {
                double r = (double) a * (double) b;

                return (float) (r - (double) this.modulus * (double) (int)
        (this.inverseModulus * r));
            }

            public float modInverse(float a)
            {
                return modPow(a, this.modulus - 2);
            }

            public float modPow(float a, float n)
            {
                long exponent = (long) n;

                while ((exponent & 1) == 0)
                {
                    a = modMultiply(a, a);
                    exponent >>= 1;
                }

                float r = a;

                while ((exponent >>= 1) > 0)
                {
                    a = modMultiply(a, a);
                    if ((exponent & 1) != 0)
                    {
                        r = modMultiply(r, a);
                    }
                }

                return r;
            }

            public static void main(String[] args)
            {
                FloatBugTest math = new FloatBugTest();
                math.setModulus(16515073.0f);
                Random random = new Random(1234);
                float s1 = 0, s2 = 0;

                for (int i = 0; i < 1000; i++)
                {
                    float x = (float) (Math.abs(random.nextLong()) % 16515073);

                    s1 += math.modMultiply(x, x); // Works
                    s2 += math.modMultiply(math.modInverse(x), x); // Buggy
                }

                System.out.println(s1);
                System.out.println(s2);
            }
        }

        ---------- END SOURCE ----------

        CUSTOMER WORKAROUND :
        You can try various modifications to the code to make it
        work. So it's probably some subtle hotspot optimization
        that goes wrong.

        For example, you can make the modMultiply() method
        strictfp. That makes it work, but the execution time
        roughly doubles!

        Or, you can change the cast to (int) in modMultiply() to a
        call to Math.floor, but that also degrades the performance
        horribly.

        As said, you can use the client VM or interpreted mode, but
        also in these cases the performance suffers greatly.

          To debug where it goes wrong I can change two methods

            public float modMultiply(float a, float b)
            {
                double r = (double) a * (double) b;

                r -= (double) this.modulus * (double) (int)
        (this.inverseModulus * r);

                check(a, b, r);

                return (float) r;
            }

            private void check(float a, float b, double r)
            {
                if ((long) r != (long) a * (long) b % (long)
        this.modulus)
                {
                    throw new Error();
                }
            }

        Then run with java -Xcomp -server FloatBugTest It prints a wrong result, but detects no error:

        8.2643241E9
        7.2639124E9

        When I change the check() call to check(a, b, (float) r);
        and run java -Xcomp -server FloatBugTest
        it prints out the correct result.

        Release Regression From : 1.4.0_01
        The above release value was the last known release where this
        bug was known to work. Since then there has been a regression.

        (Review ID: 163409)
        ======================================================================

          Attachments

            Issue Links

              Activity

                People

                • Assignee:
                  cclicksunw Clifford Click (Inactive)
                  Reporter:
                  rmandalasunw Ranjith Mandala (Inactive)
                • Votes:
                  0 Vote for this issue
                  Watchers:
                  0 Start watching this issue

                  Dates

                  • Created:
                    Updated:
                    Resolved:
                    Imported:
                    Indexed: