Hi Terry,
as pointed out by Martin, the real issue is using *binary*
floating-point arithmetic, like float or double, to emulate *decimal*
arithmetic.
When you write 0.1D in Java, C or C++, what happens is that this decimal
number is rounded to the double closest to the mathematical value 1/10.
There's no double that is exactly 1/10, so you start with a value that
is already rounded and inexact. Multiplication rounds as well, so you
end up with a value that was subject to 3 roundings: twice for the
conversion of the two openads from 0.1D to the closest doubles and once
for the multiplication. The result is slightly different than the
naively "expected" 0.01D, which is subject to one rounding only during
conversion to the closest double. In other words, 0.1D*0.1D != 0.01D,
even in C/C++ and most programming languages/environments.
In Java, however, when you convert a double to a decimal string by means
of System.out.print[ln](), the library outputs just as many digits as
necessary, and no less, for an input routine to be able to recover the
original double. C and C++ do *not* ensure this. In Java, 0.01D (1
rounding) is correctly converted to "0.01" while 0.1D*0.1D (3 roundings)
is correctly converted to "0.010000000000000002".
In C/C++, try to output both 0.1D*0.1D and 0.01D with 20 digits, say,
instead of the default 6 and you'll see a difference.
As observed by RĂ©mi, Java offers formatting similar to C/C++ if that is
what you want.
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.
HTH
Raffaello
On 3/14/22 07:49, A Z wrote:
To whom it may concern,
Having noticed
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8190947
https://bugs.openjdk.java.net/browse/JDK-8190991
and similar, at
https://community.oracle.com/tech/developers/discussion/4126262/big-issue-with-float-double-java-floating-point
I have been referred on to the core-libs-dev area.
The software development company I represent wishes to keep its name
confidential,
and no-mentioned, at this time.
A number of us at our end have found that floating point and StrictMath
arithmetic
on both float and double does not result in range accuracy, but produces
denormal
and pronormal values.
We are aware of the Java Language Specification, and IEEE 754 specifications,
to these issues, but are still finding that they are not the most relevant or
great issue.
While we are aware of the BigDecimal and BigInteger workarounds, and
furthermore, the calculator class including big-math
https://github.com/eobermuhlner,
we are finding in the development, debugging, and editing of our Java programs,
that using other classes to operate and exchange for the lack of range accuracy
from float,
double and java.lang.StrictMath, that we are getting bogged down with what
turns into
more inferior software. The known and available workaround approaches are
becoming
stop-gap measures, perforcedly put in place, while introducing other problems
into OpenJDK or Java software that don't have any particular, immediate,
solutions.
Substituting float and double data in and out of BigDecimal and BigInteger
produces
source code which is much messier, complicated, error prone, difficult to
understand
and to change, is definitely slower, and is an inferior substitute when float
and double are more than enough in the overwhelming majority of corresponding
cases.
This is particularly showing up in 2D and 3D Graphics software, by the default
OpenJDK Libraries, but also through JMonkeyEngine 3.5.
Possessing the option to immediately deal with the precondition, postcondition
and field types of float and double is far superior and more than ideal.
All this is before the massive advantage of being able to use operators,
but the change case becomes overwhelming when along a range accurate,
double (or maybe float, also) supporting Scientific Calculator class.
If I want to discuss (at least OpenJDK) change in this area, I have
been pointed to the core-libs area, by one of the respondents
of the article:
https://community.oracle.com/tech/developers/discussion/4126262/big-issue-with-float-double-java-floating-point.
Is there anyone here, at core-libs-dev, who can point
me in a better Oracle or OpenJDK direction, to discuss further
and see about Java float and double and StrictMath floating point
arithmetic denormal and pronormal values being repaired away
and being made range accurate for all evaluation operations
with them?
Certainly since other languages already have, that are open source
and open resource file ones. 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.
Consider these three different language API evaluations,
using their equivalents of float and double to perform
the floating point equivalent of that precise evaluation:
//----------------------------------------------------------
//The C Language.
#include <stdio.h>
int main()
{
printf("Program has started...");
printf("\n");
printf("\n");
double a = 0.1D;
double b = 0.1D;
double c = a*b;
printf("%lf",c);
printf("\n");
printf("\n");
float d = 0.1F;
float e = 0.1F;
float f = d*e;
printf("%lf",f);
printf("\n");
printf("\n");
printf("Program has Finished.");
return 0;
}
/*
Program has started...
0.010000
0.010000
Program has Finished.
*/
//----------------------------------------------------------
//The C++ Language.
#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.
*/
//----------------------------------------------------------
//The Java Language.
import static java.lang.System.*;
public class Start
{
public static void main(String ... args)
{
out.println("Program has started...");
double a = 0.1D;
double b = 0.1D;
double c = a*b;
out.println();
out.println(c);
float d = 0.1F;
float e = 0.1F;
float f = d*e;
out.println();
out.println(f); out.println();
out.println("Program has Finished.");
}}
/*
Program has started...
0.010000000000000002
0.010000001
Program has Finished..
*/
//----------------------------------------------------------
In order for java to introduce either default alteration,
or a compatibility mode alteration, where,
how and who should I begin to speak with?
Yours Sincerely,
Terry Neale