how to fix double precision issue in java [duplicate] - java

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Java floats and doubles, how to avoid that 0.0 + 0.1 + … + 0.1 == 0.9000001?
How can I overcome the precision issue with double multiplication in java android??Please note that I am converting a string value into double value.
eg: when I multiply two double value:
double d1 = Double.valueOf("0.3").doubleValue() * Double.valueOf("3").doubleValue();
System.out.println("Result of multiplication : "+d1);
I am getting the following result : 0.8999999999999999
Some of the results that i am getting are.
0.6*3=1.7999999999999998;
0.2*0.2=0.04000000000000001;
etc.
Instead of the above results I would like to get the following results.
0.3*3=0.9;
0.6*3=1.8;
0.2*0.2=0.04;
Please remember that I am not trying to round it to the nearest integer.

You should really be using java.math.BigDecimal to avoid any precision issues, and always use a BigDecimal(String) constructor.
BigDecimal result = new BigDecimal("0.3").multiply( new BigDecimal("3.0") );

The problem isn't with multiplication. It starts with Double.valueOf("0.3"). That value can't be represented exactly in floating-point. You should use java.math.BigDecimal, and you should also Google for a page entitled "What every computer scientist should know about floating point".

Unfortunately, I am not aware of a simple way of doing exactly what you ask for.
Like Strelok says, you should not be using a floating-point type if you need exact results. However, for most purposes, it is enough to just specify a rounding precision for output. The following code is close to, but not quite, what you want:
System.out.printf("Result of multiplication : %.1g\n", d1);
For more info on the syntax of printf, see the java.util.Formatter documentation.

Related

How to get the value without round up/down in Java? [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 3 years ago.
double d0 = Double.parseDouble("53.82233040000000557");
double d1 = Double.valueOf("53.82233040000000557");
output
d0 = 53.822330400000006
d1 = 53.822330400000006
Precision Numbers in Java
Class java.math.BigDecimal is better for handling numbers where precision matters (like monetary amounts), see BigDecimal VS double.
It could be used for geo-coordinates (latitude/longitude). Although practitionars argue that double is precise enough for lat./long. - since you don't want to locate something at nano-meter scale.
Example Code
If you need high precision and scale for your number, use BigDecimal like this:
BigDecimal decimalValue = new BigDecimal("53.82233040000000557");
System.out.println("as BigDecimal: " + decimalValue.toPlainString());
// prints exactly: 53.82233040000000557
Run this code online (IDE one): Double VS BigDecimal for high precision
Read more
Read more in a tutorial on Java: BigDecimal and BigInteger
If you need precision, you have to use a BigDecimal.
The answer is that you cannot. The values you are getting are the most accurate approximation to your values that can possibly be stored in a double. There is no possible way to get a more accurate, less rounded value stored in a double.
If you require that the answers are not rounded at all, therefore, you should not be using double. The data type you should be using instead is BigDecimal.

Formatting Double to String? [duplicate]

This question already has answers here:
Why does floating-point arithmetic not give exact results when adding decimal fractions?
(31 answers)
Closed 3 years ago.
String.format("%,.0f", 200000000000000000000000.0)
-> 199,999,999,999,999,980,000,000
why?
Understand the Double Data type - it is an approximation of amount and scale.
The Following assignment:
double d = 2.00000000000f;
will generate a value of 1.9999999 at times when printed. What you are seeing here is magnification of that. Double Data types also have a maximum (implementation-dependant) of how many places of significance they can support (upto 15 generally) - which is why the last 6 digits are all zeros (0)
For your particular solution, if you don't require Floating-point Data, stick to Integer.
It is because current processors(and most VMs) work like that if use default data types. Here it is explained in details
If you want precision use BigDecimal. This class is specifically intended for situations like this - to be used in currency related stuff and scientific calculations.
To format decimals in proper way Java has DecimalFormat
String pattern = "###,###.###";
DecimalFormat decimalFormat = new DecimalFormat(pattern);
String format = decimalFormat.format(123456789.123);
System.out.println(format); // -> 123.456.789,123
Here is nice tutorial about it
Hope it helps.
My problem has been solved
String.format("%,.0f", BigDecimal( 200000000000000000000000.0, MathContext.DECIMAL64))

Floats not adding up [duplicate]

I'm wondering what the best way to fix precision errors is in Java. As you can see in the following example, there are precision errors:
class FloatTest
{
public static void main(String[] args)
{
Float number1 = 1.89f;
for(int i = 11; i < 800; i*=2)
{
System.out.println("loop value: " + i);
System.out.println(i*number1);
System.out.println("");
}
}
}
The result displayed is:
loop value: 11
20.789999
loop value: 22
41.579998
loop value: 44
83.159996
loop value: 88
166.31999
loop value: 176
332.63998
loop value: 352
665.27997
loop value: 704
1330.5599
Also, if someone can explain why it only does it starting at 11 and doubling the value every time. I think all other values (or many of them at least) displayed the correct result.
Problems like this have caused me headache in the past and I usually use number formatters or put them into a String.
Edit: As people have mentioned, I could use a double, but after trying it, it seems that 1.89 as a double times 792 still outputs an error (the output is 1496.8799999999999).
I guess I'll try the other solutions such as BigDecimal
If you really care about precision, you should use BigDecimal
https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/math/BigDecimal.html
The problem is not with Java but with the good standard float's (http://en.wikipedia.org/wiki/IEEE_floating-point_standard).
You can either:
use Double and have a bit more precision (but not perfect of course, it also has limited precision)
use a arbitrary-precision-library
use numerically stable algorithms and truncate/round digits of which you are not sure they are correct (you can calculate numeric precision of operations)
When you print the result of a double operation you need to use appropriate rounding.
System.out.printf("%.2f%n", 1.89 * 792);
prints
1496.88
If you want to round the result to a precision, you can use rounding.
double d = 1.89 * 792;
d = Math.round(d * 100) / 100.0;
System.out.println(d);
prints
1496.88
However if you see below, this prints as expected, as there is a small amount of implied rounding.
It worth nothing that (double) 1.89 is not exactly 1.89 It is a close approximation.
new BigDecimal(double) converts the exact value of double without any implied rounding. It can be useful in finding the exact value of a double.
System.out.println(new BigDecimal(1.89));
System.out.println(new BigDecimal(1496.88));
prints
1.8899999999999999023003738329862244427204132080078125
1496.8800000000001091393642127513885498046875
Most of your question has been pretty well covered, though you might still benefit from reading the [floating-point] tag wiki to understand why the other answers work.
However, nobody has addressed "why it only does it starting at 11 and doubling the value every time," so here's the answer to that:
for(int i = 11; i < 800; i*=2)
╚═══╤════╝ ╚╤═╝
│ └───── "double the value every time"
│
└───── "start at 11"
You could use doubles instead of floats
If you really need arbitrary precision, use BigDecimal.
first of Float is the wrapper class for the primitive float
and doubles have more precision
but if you only want to calculate down to the second digit (for monetary purposes for example) use an integer (as if you are using cents as unit) and add some scaling logic when you are multiplying/dividing
or if you need arbitrary precision use BigDecimal
If precision is vital, you should use BigDecimal to make sure that the required precision remains. When you instantiate the calculation, remember to use strings to instantiate the values instead of doubles.
I never had a problem with simple arithmetic precision in either Basic, Visual Basic, FORTRAN, ALGOL or other "primitive" languages. It is beyond comprehension that JAVA can't do simple arithmetic without introducing errors. I need just two digits to the right of the decimal point for doing some accounting. Using Float subtracting 1000 from 1355.65 I get 355.650002! In order to get around this ridiculous error I have implemented a simple solution. I process my input by separating the values on each side of the decimal point as character, convert each to integers, multiply each by 1000 and add the two back together as integers. Ridiculous but there are no errors introduced by the poor JAVA algorithms.

Adding and subtracting doubles are giving strange results [duplicate]

This question already has answers here:
Retain precision with double in Java
(24 answers)
Closed 9 years ago.
So when I add or subtract in Java with Doubles, it giving me strange results. Here are some:
If I add 0.0 + 5.1, it gives me 5.1. That's correct.
If I add 5.1 + 0.1, it gives me 5.199999999999 (The number of repeating 9s may be off). That's wrong.
If I subtract 4.8 - 0.4, it gives me 4.39999999999995 (Again, the repeating 9s may be off). That's wrong.
At first I thought this was only the problem with adding doubles with decimal values, but I was wrong. The following worked fine:
5.1 + 0.2 = 5.3
5.1 - 0.3 = 4.8
Now, the first number added is a double saved as a variable, though the second variable grabs the text from a JTextField. For example:
//doubleNum = 5.1 RIGHT HERE
//The textfield has only a "0.1" in it.
doubleNum += Double.parseDouble(textField.getText());
//doubleNum = 5.199999999999999
In Java, double values are IEEE floating point numbers. Unless they are a power of 2 (or sums of powers of 2, e.g. 1/8 + 1/4 = 3/8), they cannot be represented exactly, even if they have high precision. Some floating point operations will compound the round-off error present in these floating point numbers. In cases you've described above, the floating-point errors have become significant enough to show up in the output.
It doesn't matter what the source of the number is, whether it's parsing a string from a JTextField or specifying a double literal -- the problem is inherit in floating-point representation.
Workarounds:
If you know you'll only have so many decimal points, then use integer
arithmetic, then convert to a decimal:
(double) (51 + 1) / 10
(double) (48 - 4) / 10
Use BigDecimal
If you must use double, you can cut down on floating-point errors
with the Kahan Summation Algorithm.
In Java, doubles use IEEE 754 floating point arithmetic (see this Wikipedia article), which is inherently inaccurate. Use BigDecimal for perfect decimal precision. To round in printing, accepting merely "pretty good" accuracy, use printf("%.3f", x).

Java precision during division and multiplication alterneting process [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to resolve a Java Rounding Double issue
Please Help,
I programm some calculator in Java. I use double type. Double has 15 digits after the decimal point. I have problem with the following:
1/3 * 3 = 0.9999999999999999
I need 1/3 * 3 = 1
How can I solve this problem?
I keep result in Double. The same problem I have with other mathematical operations, for example
sqrt(6) = 2.449489742783, and next I square the result and I get: 5.999999999999999
You're dealing with inherent limitations of floating-point arithmetic.
Read the paper What Every Computer Scientist Should Know About Floating-Point Arithmetic.
For equality-checking, you should be using something like abs(x-y) < epsilon rather than x == y
For display purposes, you should round to the nearest decimal place that you actually care about.
Certain numbers cannot be represented exactly in binary floating point. 1/3 is one of them. See http://en.wikipedia.org/wiki/Floating_point For that matter, 1/3 cannot be represented exactly in decimal either.
Your calculator should use a java.text.NumberFormat to present the numbers.
The reason why you are seeing this is due to the computers inability to understand infinity.
A computer has limitations, so it does not understand the fact that 1/3 is never-ending. This causes it to round. This can be solved as Jason S posted above. Using these special class, people have started to program ways to computer whether or not something goes to infinity, then attempt to deal with it.

Categories

Resources