[CrossP] Java/C++ floating point mismatchs
Hi,
I have posted the following to "General Programming" without success, maybe people here could be more helpful. Sorry for the inconvenience.
-- -- --
I need to port some C++ code to Java. I cannot copy it here, but I think it is not important.
It is scientific computation, namely computation of integrals using usual discreet methods.
I have very basically translated the C++ calculation code to Java (this can be done very easily thanks to the identical syntax). float are used everywhere.
But the numerical results are _very_ different. The ratio can be as high as 2 or 3. This is very problematic, as you can imagine.
Using double did not help much.
Is there any known difference in the way floats are handled in Java (1.4) and C++ (VisualStudio)?
If this is the case, is there some easy workarounds?
In particular, I don't have the 'semantic' of the calculus being made. I have to rely solely on the C++ code. I would prefer, as far as possible, to translate it. I can hardly rewrite the work from scratch.
--More exactly--
I can't past the code.
But it is irrelevant: it is 1000+ lines of C++ simply translated in Java (it is only imperative programming here, there is no object involved). In fact there is no real translation since the syntax is nearly identical in such a case.
My problem is that the numerical results are highly divergent.
My question is: if Java and C++ handled floats the same way (and they are supposed to, it is the same IEEE 754), the numerical results should be the same.
But they're not.
Hence, there must be an (possibly) undocumented difference between Java and C++.
I think C++ has been out there for long enough: any discrepancy should be known.
I fear that Java may have broken the standard. Can anyone help on this? Confirm, or not?
If this is actually the case, can this be easily fixed, how?
If not, what the f*ck is happening?
Regards.
[2026 byte] By [
nbalpmma] at [2007-9-30 1:21:20]

Hello!
Well the standard Java follows for floating-point numbers is IEEE 754.
Actually java standard demand all float point and math operation follow the standard so the same code give you exactly the same result on ANY platform and any VM.
There was lots of benchmarks and discussions about the issue c++/java in two words i's c++ which doesn't follow the "standard" it depends from the platform, compiler and optimization keys.
Cheers,
D.
C and C++ compilers often take shortcuts when performing floating point operations
and rely heavily on the underlying hardware implementation (though there are
options to enable or disable this behaviour). Hardware implementations of FP
operations are often inaccurate in that they do not perform full accuracy
computations (the results are correct they often don't have the expected precision). This is not normally a problem and can produce substantial
performance improvements.
Java uses a well defined and standard set of floating point and trig functions. These enable the same result to be obtained for the same calculation on ALL
platforms irrespective of the underlying hardware.
As for your errors. Well, I would first suspect that you have made a mistake
somewhere as the differences between results from the Java and C operations should
not be particularly big. However if you are performing iterative computations such
as integration then it is possible that a small difference at the begining of a
computation could result in pretty large differences after a few hundred
iterations.
matfud
Consider a++ + b++, modulo and others.Build-in tracing in both C++ and java, and then narrow all down.System.out.println("a=" + (int)(a * 1000));That guarantees some correctness.
> But the numerical results are _very_ different. The
> ratio can be as high as 2 or 3. This is very
> problematic, as you can imagine.
> Using double did not help much.
I have ported code from C and C++ to Java with very few problems. Most of the differences in computational results are very very small.
I would suggest that either
1) you have not ported the C++ correectly or
2) the problem you are trying to solve is very sensitive and therefore should be reformulated.
You have been given good advice in the other thread! Did you expect them to say that you have done everything right and that it is the fault of Java that your resuts don't match?Get real.
A sumarize follows, you found the problem. But I still need help to fix it. Thks.
--
Hi all, and thanks: some of you have pinpoint what I think is the real problem.
First of all, I'd like to excuse myself: I didn't not intend to be agressive or "closed-minded".
In some case, you don't have the right to post your source. Moreover, I suspected that the problem was not coming from the translation, ang I gave arguments in this way. I was not interested in answers focused on the code: I wanted to know whether there could be an independent problem (this doesn't mean I am overconfident: I can debug the code myself; but I can't do that if there is another problem. And in fact, there seems to be one)
In fact, Java is not at fault, some articles on the web lead to think it could have:
http://www.sonic.net/~jddarcy/Borneo/
I thought that usual implementations of C/C++ were using IEEE 754 by default. But in fact they don't, unless you provide the appropriate compile-time option, as some of you remarked. To quote matfud, on the forum Algorithms:
"C and C++ compilers often take shortcuts when performing floating point operations
and rely heavily on the underlying hardware implementation (though there are
options to enable or disable this behaviour). Hardware implementations of FP
operations are often inaccurate in that they do not perform full accuracy
computations (the results are correct they often don't have the expected precision). This is not normally a problem and can produce substantial
performance improvements.
Java uses a well defined and standard set of floating point and trig functions. These enable the same result to be obtained for the same calculation on ALL
platforms irrespective of the underlying hardware."
In my particular case, the algorithms used are known to be unstable. There is nothing I can do about that (not my choice though). But it would not have been a problem if my C++ compiler (+ CPU) and Java were doing exactly the same thing. But they don't.
But if the original question is answered, this is not enough.
I am not free with this project: I have to follow the C++ program results, so I cannot compile it with the appropriate flag. The C++ program and the Java one will behave the same: but it won't stick to the original results. Those are to be respected, whatever it costs. Even if they can be considered as wrong in some way (to a computer scientist,say), they are "right" by hypothesis...
And as I explained, the computations are not mathematically specified, and can't be by "calling someone". There is no such "someone".
What I would need is to force Java to adopt the "default" behaviour of (Visual) C++ on a pentium. I cannot do otherwise: I can't change the sources past some low level changes (lack of spec), and I can't change the C++ program behaviour (and in particular its numerical results), even if it is the one which is broken.
So is there a way to force Java to adopt fast FP type calculations (~80 bits of precision in memory)?
If the bit level computations are the same, _exactly_ the same I mean, hence the problem, if there is still one, will come only from the translation. But right now, the latter cannot be addressed if I use standard Java floats (which are standard-compliant here).
I know this is weird and non-orthodox, and whatever else you want... but I fear I have no choice.
Best regards, and thanks to all of you.
If you want the behaviour of the C++ code then your simplest option is to compile the C++ as a dynamic
link library and call it directly from your java implementation.
Otherwise there is little you can do to make java perform the same as the C or C++ without
reimplementing the JVM and and the Math package.
http://java.sun.com/docs/books/jls/strictfp-changes.pdf
describes the behaviour in more detail.
Basically a JVM can implement float/double operations in anyway it sees fit unless the operation
is declared strictfp. Strictfp means that results are made to be members of either the float set or the
double set (intermediate 80bit floats are not allowed). However if your expressions are not strictfp
then you cannot guarentee how the JVM stores the values.
If you are using trig functions in your code then these are most likely the source of your problems.
The trig functions used by VC++ (by default) are only accurate to 6 or 7 significant places. Those in
java are accurate to the full precision of float (or double).
A second source of discrepency could be with compile time constants. In java all expressions that can
be evaluated at compile time are strictfp and hence limited to 32 or 64 bit accuracy. (not sure how
this is different from C but is somthing to consider)
matfud
If two numerical (correct) solvers S1 and S2 produce different results by an order of magnitude
for a certain problem P, i.e. S1(P) != S2(P) +/- eps, one can be certain that this problem P is
very badly conditioned (unstable). Division by near zero values, numerical rank degradation
and all those other beasts roar their ugly heads.
A very nasty, filthy, dirty, naughty trick exists though. The proponents of this very nasty, filthy,
dirty naughty trick prefer to call it perturbation. Think of it this way -- in an orthogonal
space one has to find a minimum/maximum whatever, while steep edges, worm holes etc.
form show-stopping obstacles for solvers S on their way to the solution. Perturbation
slightly twists that orthogonal space a bit, hopefully guiding the solver close to the edge of
those worm holes, steep edges, summits etc.
It all boils down to the following -- anywhere along the search path towards the solution
slightly alter the values of the intermediate results by a percentage < epsilon. The last
value needs to be (very) small. (Pseudo) random number generators are essential here.
Repeat the calculation/iteration a couple of times. I one solution shows up more often than
the others, pick that solution but realize that the 'real' value may be off by a percentage epsilon.
I consider it a filthy, dirty, naughty trick and I solemnly swear that I've never used it myself.
Well ... *cough* maybe once or twice ... by accident that was ... I think ;-)
kind regards,
Jos
> Is there any known difference in the way floats are
> handled in Java (1.4) and C++ (VisualStudio)?
Yes - if you are using any trigonemtric functions then C++ is INACCURATE.
There also could be potential differences if you are specifying any numeric
constants incorrectly -- are you using ANY numeric constants that do not
have a decimal point? Are you putting "f" or "d" on the end (i.e. 1234.567d)?
> Yes - if you are using any trigonemtric functions then C++ is INACCURATE.
With all due respect, I think this is uncalled for w.r.t. C++. Admitted, there exist badly designed and
implemented floating point libraries and even FPPs, but that's not C++ to blaim is it?
kind regards,
Jos
> > Yes - if you are using any trigonemtric functions
> then C++ is INACCURATE.
>
> With all due respect, I think this is uncalled for
> w.r.t. C++. Admitted, there exist badly designed and
> implemented floating point libraries and even FPPs,
> but that's not C++ to blaim is it?
If the C++ implementation is using the x87 FPU, then yes, it is.
From: http://developer.java.sun.com/developer/bugParade/bugs/4857011.html
The x87 FPU has fsin and fcos instructions to accelerate the
computation of sine and cosine. However, these instructions have a
number of limitations. First, they only return sensible results over a
limited range of values, +/- 2^63. Java's sin/cos functions are defined
over the full double range, roughly +/- 2^1023. Second, even within
the +/-2^63 range, nearly all fsin/fcos implementations perform faulty
*argument reduction,* consequently, the results can be very wrong
outside of a narrow range of +/- pi/4.