Negative zero is definitely a thing in Java for primitive doubles - use Double.compare(double,double) to check for negative zeroes. In jshell:
jshell> Double.compare(-0.0, 0.0)
$1 ==> -1
jshell> Double.compare(0.0, 0.0)
$2 ==> 0
jshell> Double.compare(0.0, -0.0)
$3 ==> 1
With that said, I wasn't aware that boxed doubles/floats in GWT don't quite behave as they do in the JVM, for zeroes and NaNs when boxed or in arrays:
https://github.com/gwtproject/gwt/commit/86c02879071b6690e347a1d255f551619c99f9e6
This almost certainly isn't related to your issue though, which as you've noted, is JVM vs JVM.
Are you able to instrument the simulation at some kind of checkpoint (ideally per-calculation, but something coarser should help too), and then record one JVM's results as it runs, then have the other check its work to find the first point where it differs? That should help you work backwards to the actual point of divergence, ideally to understand which operation introduced the divergence, then get to why there is such a difference?
On Monday, May 12, 2025 at 11:00:44 PM UTC-5 ma...@craig-mitchell.com wrote:
I tried moving my tests out of JUnit, and into my main application (I can trigger them from an admin tool).- Running in JavaScript in the browser. Consistent and correct results.
- Running in Java Springboot on Google App Engine with an Undertow webserver. Inconsistent and incorrect results. Ie: I run the test once and get one result, run it again and it gives me a different result.
- Running locally on my Windows PC (instead of Google App Engine). Same inconsistent and incorrect results.
I also tried switching to use Tomcat instead of Undertow. No difference.
The head scratching continues ...
On Tuesday, 13 May 2025 at 12:13:00 pm UTC+10 Craig Mitchell wrote:
Removed the Doubles. It didn't solve it.
Bit of a long shot in hindsight, as getting different results from Java based on if I run the test via "mvn test", or via IntelliJ, is still the red flag.
On Tuesday, 13 May 2025 at 10:12:56 am UTC+10 Craig Mitchell wrote:
Thanks all. I'm not using DoubleSummaryStatistics or any JNI.
One thing I noticed when I was logging my calcs, trying to compare the differences between Java and JavaScript, I would sometimes get -0.0 for a double.
Turns out there is a difference between 0.0 and -0.0, but (I think) only when using Double, not double (which I have in a few places). Ie:
Double a = 0.0;
Double b = -0.0;
if (a == b) System.out.println("yes");
else System.out.println("no");
Prints "no".
While in GWT:
Double a = 0.0;
Double b = -0.0;
if (a == b) GWT.log("yes");
else GWT.log("no");
Prints "yes".
I'll now remove all "Double"s from my code and see if that fixes it. Fingers crossed!
On Tuesday, 13 May 2025 at 5:13:31 am UTC+10 Colin Alworth wrote:
Any chance you're using any JNI libraries in your JVM implementation? I recently became aware that gcc-compiled libraries with -ffast-math and friends can result in subnormal values doing unexpected things, causing inconsistent/incorrect results for some well defined operations. Unfortunately that flag can cause gcc to emit x86 assembly that makes global changes to how a process interacts with these numbers.
It appears that Java 22+ has mitigation for this, by testing in at least some cases if these features have been used and then attempting to restore the expected state for Java:
My read is that this is technically incomplete, since it only happens at loadLibrary() time, and technically any call into JNI could re-set these flags.
On Monday, May 12, 2025 at 10:50:08 AM UTC-5 Jens wrote:
It is really weird that your results do not match. Prior Java 17 the "strictfp" keyword could be used to force the JVM to not cheat a little. But since Java 17 it is the default and the keyword does nothing anymore (https://openjdk.org/jeps/306). So the results should be portable now.
In case you are using DoubleSummaryStatistics in your code, GWT emulation uses Kahan summation to compensate for rounding errors but I think Java uses the same algorithm. However JavaDoc of DoubleSummaryStatistics.getSum() leaves room to have different implementations and error compensations. It explicitly says that the output may vary for the same input.
-- J.
Craig Mitchell schrieb am Montag, 12. Mai 2025 um 15:45:15 UTC+2:
The results from GWTTestCase match JavaScript!
It's rather slow though. Running the same test in these envs:
- Java: 184ms.
- JavaScript (Chrome): 3.5 seconds.
- GWTTestCase: 5.8 minutes.
On Wednesday, 30 April 2025 at 3:39:57 pm UTC+10 Craig Mitchell wrote:
> I meant that IntelliJ run configuration for JUnit has an option forkmode and I am pretty sure the maven plugin also has an option for JVM forking. For example you can configure that every test method should run in a forked VM in IntelliJ. By default it doesn't do that.
Ah, cool, thanks. I see that option now.
With it on, I get different results again. Different to maven, different to no fork, and different to JavaScript.
And if I run it through Maven with "mvn test -DforkCount=1 -DreuseForks=false", I get results that are completely different again.
They are still consistent though. Ie: Running it multiple times, always gets the same results.
On Tuesday, 29 April 2025 at 8:34:25 pm UTC+10 Jens wrote:
> Maybe the result slightly changes if JVM decides to optimize a hot code path in case the JVM is reused. You might want to check how maven and your intellij run configuration are configured in terms of JVM forking.
IntelliJ seems to add the options:
-Dkotlinx.coroutines.debug.enable.creation.stack.trace=false -Ddebugger.agent.enable.coroutines=true -Dkotlinx.coroutines.debug.enable.flows.stack.trace=true -Dkotlinx.coroutines.debug.enable.mutable.state.flows.stack.trace=true -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8
So I added those to MAVEN_OPTS, but it didn't seem to make any difference. I also tried adding @NotThreadSafe to my test suite, again no difference.
I meant that IntelliJ run configuration for JUnit has an option forkmode and I am pretty sure the maven plugin also has an option for JVM forking. For example you can configure that every test method should run in a forked VM in IntelliJ. By default it doesn't do that.
-- J.
--
You received this message because you are subscribed to the Google Groups "GWT Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to
google-web-toolkit+unsubscribe@googlegroups.com.
To view this discussion visit
https://groups.google.com/d/msgid/google-web-toolkit/ef449eeb-2c53-4773-9811-d03adf40ff53n%40googlegroups.com.