[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]
# 1

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.

D_Repa at 2007-7-16 5:57:39 > top of Java-index,Other Topics,Algorithms...
# 2

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

matfuda at 2007-7-16 5:57:39 > top of Java-index,Other Topics,Algorithms...
# 3
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.
joop_eggena at 2007-7-16 5:57:39 > top of Java-index,Other Topics,Algorithms...
# 4

> 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.

sabre150a at 2007-7-16 5:57:39 > top of Java-index,Other Topics,Algorithms...
# 5
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.
sabre150a at 2007-7-16 5:57:39 > top of Java-index,Other Topics,Algorithms...
# 6

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.

nbalpmma at 2007-7-16 5:57:39 > top of Java-index,Other Topics,Algorithms...
# 7

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

matfuda at 2007-7-16 5:57:39 > top of Java-index,Other Topics,Algorithms...
# 8

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

JosHorsmeiera at 2007-7-16 5:57:39 > top of Java-index,Other Topics,Algorithms...
# 9

> 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)?

rkconnera at 2007-7-16 5:57:39 > top of Java-index,Other Topics,Algorithms...
# 10

> 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

JosHorsmeiera at 2007-7-16 5:57:39 > top of Java-index,Other Topics,Algorithms...
# 11

> > 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.

rkconnera at 2007-7-16 5:57:39 > top of Java-index,Other Topics,Algorithms...