Discussion about Java Floating Point?

Raffaello Giulietti raffaello.giulietti at gmail.com
Tue Mar 15 10:23:19 UTC 2022


Sorry, for some reason a line was missing in the C++ code


#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 << "0.1D*0.1D : ";
     cout.precision(30);
     cout << c << endl;
     cout << "0.01D     : ";
     cout.precision(30);
     cout << d << endl << endl;
     cout << "Program has finished." << endl;
     return 0;
}



On 3/15/22 11:03, Raffaello Giulietti wrote:
> 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