Discussion about Java Floating Point?

Raffaello Giulietti raffaello.giulietti at gmail.com
Tue Mar 15 10:03:27 UTC 2022


Hi,

Java, as well as most implementations of most languages, including C and 
C++, have adopted the IEEE 754 floating-point standard, first issued in 
1985. The standard specifies the formats, the outcome of operators and 
comparisons up to the last bit.

Try out this C/C++ code (I'm on Linux with gcc)



#include <iostream>

using namespace std;

int main()
{
     cout << "Program has started..." << endl;
     double a = 0.1D;
     double b = 0.1D;
     double c = a*b;
     double d = 0.01D;
     cout << endl << "0.1D*0.1D " << (c == d ? "==" : "!=") << " 0.01D" 
<< endl << endl;
     cout.precision(30);
     cout << c << endl;
     cout << "0.01D     : ";
     cout.precision(30);
     cout << d << endl << endl;
     cout << "Program has finished." << endl;
     return 0;
}



This is the output I see:



Program has started...

0.1D*0.1D != 0.01D

0.1D*0.1D : 0.010000000000000001942890293094
0.01D     : 0.0100000000000000002081668171172

Program has finished.



So 0.1D*0.1D != 0.01D, as stated on my previous post. That is, 
expectations on decimal behavior are usually wrong. It is inherently, 
mathematically *impossible* to emulate decimal behavior with binary IEEE 
754 arithmetic. That's why Java also offers java.math.BigDecimal, a 
decimal floating-point library implemented in software.

Also, as suggested in that post, incrementing the precision of the 
output by means of precision(30) as done above, for example, also 
clearly shows where the two values start being different, with 0.1D*0.1D 
being slightly greater than 0.01D.

Note that the precision only directs how many digits appear in the 
decimal output: it doesn't affect the underlying floating-point 
arithmetic at all. The latter follows the spec in full. In fact, all 
operators and comparisons are implemented directly in hardware, not in 
libraries. All CPUs designed in the last couple of decades implement 
IEEE 754.

This shows that the default precision for decimal output in C/C++ is not 
sufficient to expose the difference between the values. You have to set 
a higher precision to see differences.

This also shows the advantage of the default Java conversion routine, as 
opposed to the default precision in C/C++: different values are 
converted to different decimal outcome, without you having to set 
anything, because Java adapts the precision of the output automatically, 
depending on the value.

Finally, while Wikipedia is an exceptional source of information, the 
ultimate authoritative reference are the IEEE 754 spec, the C/C++ specs 
and other languages specs, and their related standard libraries specs.


Greetings
Raffaello


On 3/15/22 05:23, A Z wrote:
> To core-libs-dev at openjdk.java.net,
> 
> In terms of floating point, it seems there are thus
> three (3) phenomena that are relevant.
> 
> 1) Arithmetic on float and double, via operators.
> 2) Elementary function calls, namely
>     those made from java.lang.StrictMath, as it is,
>     on double values.
> 3) Comparison operators.  ==, !=, >, <, >=,<=.
> 
> Java floating point successfully has 3) the way required,
> even though other languages, particularly C++ , do not
> compare their floats and doubles through those comparison
> operators.  The point at issue is Java although, so Java is
> satisfactory at point 3).
> 
> My point of contention is that Java does not have 1) and 2)
> operating as they should, even though C++ and other
> languages do, in those two areas, namely C++:
> 
> Martin has submitted the following:
> ?The following statement is not entirely true when using finite floating
> point precision:
> 
>> (?snip?) It is a mathematical fact that, for
>> consistent, necessary and even fast term, 10% of 10% must
>> always precisely be 1%, and by no means anything else."
> /*
> #include <iostream>
> 
> using namespace std;
> 
> int main()
> {
>      cout << "Program has started..." << endl;
>      double a = 0.1D;
>      double b = 0.1D;
>      double c = a*b;
>      cout << endl << c << endl << endl;
>      float d = 0.1F;
>      float e = 0.1F;
>      float f = d*e;
>      cout << f << endl << endl;
>      cout << "Program has Finished.";
>      return 0;
> }
> */
> /*
> Program has started...
> 
> 0.01
> 
> 0.01
> 
> Program has Finished.
> */
> 
> This is actually not fully or finally true, including SSE, SSE algorithm logic and further.
> The included C++ example of mine above here disproves this.  Even though I do
> contextually admit these answers can only work within the range of the
> involved types, it is still actually the case that 10% of 10% can and always
> precisely be 1%, within the range of the type used, and by no means
> anything else.  Because of the laws of decimal arithmetic.
> 
> See https://en.wikipedia.org/wiki/Floating-point_arithmetic
> and the starting sentence:
> 
> 'In computing, floating-point arithmetic (FP) is arithmetic using formulaic
> representation of real numbers as an approximation to support a
> trade-off betwee range and precision.'
> 
> However, it simply isn't the case that reduced precision has to exist inside
> the range, certainly not any more.  Rationally, one would have to think,
> with the present SSE support in ubiquity, and the preimplementation
> that is possible and already around elsewhere, that this kind of tradeoff
> in floating point isn't any kind of use or advantage any more.
> 
> This is part of the issue with Java and the OpenJDK at this time, and I am trying
> to contend that this should be changed, either at default or in
> some mutual compatibility mode.  The other part is java.lang.StrictMath,
> since it generates denormal and pronormal values on its own, also.
> 
> Raffaello has stated:
> To summarize, Java uses IEEE 754 binary arithmetic as by specification,
> as do most other languages, including C/C++. It is however fundamentally
> wrong to use binary floating-point arithmetic to emulate decimal
> behavior. Also, pay attention to the output routines that convert float
> and double values to a decimal representation. Usually, C and C++ will
> have information loss by default, as in your case.
> What we and others are beginning to need to happen, in detailed Java 2D
> and 3D (JMonkeyEngine 3.5) projects, and more widely again, is that Java
> floating point arithmetic and function behaviour, on float and double,
> within their ranges, do need to perfectly match decimal behaviour.
> 
> C++ arithmetic, at least, has had no problem using floating point arithmetic,
> at least, to emulate decimal behaviour.  I am trying to prove the opposite to
> Raffaello's statements, that floating point can and indeed must represent decimal behaviour.
> Output functions in any language that alter the appearance of the float or double
> value become irrelevant, because the only relevant factor is the operator behaviour
> and the innate, representation viewpoint of those float or double values.
> 
> In contrast to Raffaelo, we assert that Java SE and OpenJDK floating point must be changed
> so that it upholds base ten (10) arithmetic, algebra,and elementary functions on real value
> arguments within the ranges of double and/or float.  Alongside a calculator class that upholds
> the same.  These are in keeping with the Wikipedia view on floating point arithmetic that I
> quoted earlier, but more than that, they are in keeping with the standards/specifications of
> Mathematics, and not just an idea that grew in computer science.
> 
> I wish to still request that this matter be pursued, despite Java's stance on this matter,
> in terms of the JRE for a very long time now.
> 
> While it is the case that JDK-8190991 does exist, and should continue, JDK-8190947
> has been too blithely swept away. See: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8190947
> The explanation 'Closing this enhancement as will not fix' does nothing to explain why the advantages
> of floating point repair have been turned away, and in fact, not apprehended specifically in Java.
> 
> Is there someone who can look deeper into this matter, and implement arithmetic and Calculator class
> changes for the next release version of SE and OpenJDK?
> 


More information about the core-libs-dev mailing list