-
Bug
-
Resolution: Fixed
-
P3
-
1.4.1
-
fcs
-
x86
-
windows_nt
-
Verified
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-2057673 | 1.4.2 | Clifford Click | P3 | Resolved | Fixed | b02 |
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)
======================================================================
- backported by
-
JDK-2057673 REGRESSION: Floating-point code works incorrectly with Server VM
-
- Resolved
-