Getting wrong answer in double arithmetic in Java [duplicate] - java

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Double calculation producing odd result
I'm writing a program in Java that deals with a lot of double arithmetic. I eventually get to the point where I need to add 0.6666666666666666 and -0.666666666666667. However, the answer that I get is -3.3306690738754696E-16.
In other words,
double d1 = 0.6666666666666666;
double d2 = -0.666666666666667;
System.out.println(d1 + d2);
prints out "-3.3306690738754696E-16". Why is this happening?
Thank you in advance.

doubles are not perfectly accurate, and not every decimal can be perfectly represented as a double (see this). For all practical purposes, -3.3306690738754696E-16 is 0 *. However, if you need more precision, use BigDecimal. Keep in mind that this alternative will not be nearly as efficient as using primitive doubles. It's up to you to decide if you need this level of accuracy and to make a choice accordingly.
*: Evidently, that number is not exactly zero, but for the majority of real-world calculations and computations, a value that small would be inconsiderable. In meters, this value is smaller than the diameter of protons and neutrons - i.e. very very small. That's what I mean by "for all practical purposes".

double values cannot represent all values precisely and this is such an example. You can use BigDecimal instead:
BigDecimal bd1 = new BigDecimal("0.6666666666666666");
BigDecimal bd2 = new BigDecimal("-0.666666666666667");
System.out.println(bd1.add(bd2));
Output:
-4E-16

Related

How to work with very tiny float numbers without precision loss? [duplicate]

This question already has answers here:
Java floating point high precision library [closed]
(4 answers)
Closed 9 years ago.
I read here and there explanations about how to deal with big numbers and it seems that the same class BigNumber can also be used for very small numbers.
However I cannot figure out how to make it work without losing precision.
I have numbers like 0.0000000000012 that I want to use in an equation but I dont know how to create this number with BigNumber (if that is wwhat I should use) and then how to avoid to lose precision when i turn it into a double to use in my equation.
Should I put every number used in hte equation as a BigDecimal (even the one with simple values(12, 0.1,...) or only 0.0000000000012 should be a BigNumber and I can be sure I wont lose precision?
Thank you in advance for your help,
Regards,
B.
Use the class BigDecimal. It can be used to represent decimal numbers of arbitrary precision.
To create a BigDecimal from a literal which is too precise to be represented by a double, use the string constructor:
BigDecimal almostOne = new BigDecimal("0.999999999999999999999999999999999999999987", MathContext.UNLIMITED);
When you convert them into doubles you lose precision. Therefor the BigDecimal class has various methods to perform basic arithmetics while retaining precision:
BigDecimal exactlyTen = new BigDecimal(10);
BigDecimal almostTen = almostOne.multiply(exactlyTen);
When your code is performance-critical, I recommend the question "What to do with Java BigDecimal performance?" as further reading.
String number = "0.0000000000012";
BigDecimal decimal = new BigDecimal(number);
System.out.println(decimal.toString());
decimal = decimal.multiply(new BigDecimal(1000000000000L));
System.out.println(decimal.toString());
here is the code how you can use and test BigDecimal Number run this code.
Fir sysout will return 1.2E-12 which is eq to 0.0000000000012.
To test this multiply this with 1000000000000 result to 1.2. that means you won't lose your precision.
You don't have to use BigDecimal unless you have more than 15 significant digits of precision. You do have to use appropriate rounding which is something BigDecimal helps you with but it doesn't mean you can't do the same with double.
double d = 0.0000000000012;
BigDecimal bd = BigDecimal.valueOf(d);
System.out.println("before d: " + d + " bd: " + bd);
d *= 1000000000000L;
d = Math.round(d * 1e2) / 1e2; // round to two places
bd = bd.multiply(BigDecimal.valueOf(1000000000000L));
System.out.println("after d: " + d + " bd: " + bd);
prints
before d: 1.2E-12 bd: 1.2E-12
after d: 1.2 bd: 1.2000000000000
In terms of performance double out performs BigDecimal by a factor of 100x. BigDecimal also creates lots of garbage whereas double doesn't produce any. Creating lots of garbage is not only slow but slows down all the rest of your code by filling your CPU caches with garbage.
how to avoid to lose precision when i turn it into a double to use in my equation.
With double you need to keep track of the precision yourself. This is only a problem if you have functions which have no idea of the precision and you cannot tell them and need to pass on the value. i.e. you have no chance of rounding the answer.

number formatting [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why not use Double or Float to represent currency?
I'm learning Java so please bear with me for such a simple question. When given a calculation to calculate interest i have this code inputted:
public double calculateTotal(double rate, int n)
{
amount = amount * Math.pow((1+rate), (n/12));
return amount;
}
This returns the answers I'm looking for but keeps adding 0.000000000001 onto the end.
How would i solve this? A friend advised something called number formatting but i couldn't find a solution.
This problem is related to widely known floating point calculation issue.
One of the solutions could be use of import java.math.BigDecimal
Minimizing the effect of accuracy problems article describes the
problem.
Take a look at this ticket Calculation problem in Java
EDIT
Java does not allow to override operators so the only way to add BigDecimals together is by using add method e.g. (assuming your amount is BigDecimal. Bear in mind that BigDecimal is immutable so whatever is returned from calculateTotal needs to be assigned back to ammount
// you assign result to amount outside calculateTotal
amount.add(new BigDecimal(Math.pow((1+rate), (n/12))));
or
// you assign sum to amount inside calculateTotal
amount = amount.add(new BigDecimal(Math.pow((1+rate), (n/12))));
As it was mentioned before BigDecimal is good option if you need better precision with doubles.
There is nice way to do rounding with BigDecimals. Basically you have to specify scale of the BigDecimal instance. Take a look at this sample code:
BigDecimal decimalOne = new BigDecimal(0.1950);
BigDecimal decimalTwo = decimalOne.setScale(2, BigDecimal.ROUND_HALF_DOWN);
BigDecimal decimalThree = decimalOne.setScale(4, BigDecimal.ROUND_HALF_DOWN);
System.out.println("decimalOne: " + decimalOne);
System.out.println("decimalTwo: " + decimalTwo);
System.out.println("decimalThree: " + decimalThree);
Java 7 would print something like this:
decimalOne: 0.195000000000000006661338147750939242541790008544921875
decimalTwo: 0.20
decimalThree: 0.1950
Please note that BigDecimal instances are immutable and that's why you have to assign result of setScale to new instance (decimalOne will not be changed).
In many financial system doubles are not used to store currency information; long type with specific precision is used instead e.g. for precision 2, value 100 would be 1.00, 122 would be 1.22 etc. That approach simplifies and seeds up calculations but it is not good for all the systems. However for simplicity of that question I won't dive into that subject too much.

Java sum of all double does not return expected result [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Moving decimal places over in a double
Why is the following sum of numbers not equal to 0.4622? but 0.46219999999999994
Double total = new Double(0.08) + new Double(0.0491) + new Double(0.3218) +
new Double(0.0113) + new Double(0.0); // = 0.46219999999999994
I have an application that checks the users input.
The user inputs 5 decimal numbers and a total number. The application checks if the sum of all 5 numbers capped at 4 decimals behind the komma is equal to the total number.
Capping it gives me 0.4621 which is not equal to 0.4622. I can't use DecimalFormat because it rounds it up. And if i explicitly say, round down then it will fail for this situation.
Any suggestion for how I can solve this?
Try with java.math.BigDecimal. Double rounds result. You will just have to use add method, not + operator.
Avoid using float and double if exact answers are required-- Item 48 -- Effective Java Second edition
Use BigDecimal instead.
Looks like a classic case of floating point arithmetic. If you want exact calculations, use java.math.BigDecimal. Have a look at What Every Computer Scientist Should Know About Floating-Point Arithmetic
When you use floating point arithmetic you must also use appropriate rounding.
BTW: Don't use an object when a primitive will do.
double total = 0.08 + 0.0491 + 0.3218 + 0.0113 + 0.0;
System.out.printf("%.4f%n", total);
double rounded = Math.round(total * 1e4) / 1e4;
if (rounded == 0.4622)
System.out.println("rounded matched");
prints
0.4622
rounded matched
as expected.
Double and float in Java are internally represented as binary fractions and can therefore be not precise in representing decimal fractions (IEEE standard 754). If your decimal number calculations require precision, use Java.math.BigDecimal.
Floating point representation is a close approximation so you will have these little rounding errors when you use float and double. If you try to convert 0.08 to binary for instance you will realize that you cannot actually do it exactly. You need to consider this whenever you use double and float in calculations.
0.0810 = 0.00010100011110101110...2
a repeating pattern. So no matter how many bits you use this will have a rounding error.
That is yet another rounding issue. You should never compare doubles and expect them to be exactly equal. Instead define a small epsylon and expect the result to be within epsylon of the expected answer.
Any floating point value is inexact. The solution is to use DecimalFormat when you have to display the values. And no, it doesn't round up but to the nearest value.
From the javadoc :
DecimalFormat uses half-even rounding (see ROUND_HALF_EVEN) for
formatting.
The internal representation of floating point numbers like Double is never a exact one. This is why during calculations such errors can occur.
It is always suggested to format such a result to a specific number of digits past the comma, so you result would be correctly be display as "0.4622" with 4 to 15 or more digits.
Perhaps checking the string input directly would be more feasible for you. That is check the length of characters after the decimal place.

Using Java doubles (or anything else) to store simple fractions [duplicate]

This question already has answers here:
Division of integers in Java [duplicate]
(7 answers)
Closed 7 years ago.
This seems like a very simple error:
double quarter = 1/4;
Is giving
0.0
Anybody know why this might be happening?
I am trying to store pretty much all the fractions from 1/2 to 1/20 (Just the ones with 1 on the top and in int on the bottom), so I won't be able to input the decimal straight away for all of them.
I've read and heard that floating-point datatypes are not a good way of storing fractions, so is there any other way (in Java)?
Try:
double quarter = 1d/4d;
The division of two integers gives a truncated integer. By putting the d behind the numbers you are casting them to doubles.
For starters, you're trying to divide 1/4 as integer values, and it's truncating it. 1. / 4 will correctly give you 0.25; other ways to express the number 1 as a double include 1d, 1.0, and so on.
Other approaches include:
Use BigDecimal to store values to an exact decimal precision. (For example, this is the preferred way to deal with monetary values.)
Use a Fraction or Rational class, either rolling your own or using one from a library. Apache Commons has Fraction and BigFraction, though their documentation seems a little sketchy.
Java is performing integer division because your denominator is an integer.
Try the following:
double quarter = 1 / 4.0;
Or:
double quarter = 1 / (double) 4;
The reason you're getting 0.0 is because the division is done as an integer division and then the result is converted to float. Try this, for example: double quarter = 1.0/4.0; - you should get (pretty much) the expected result.
However, depending on your requirements, this may not be the best way to deal with the problem. For example, you can't store 1/3 in a decimal. The perfect way would be to store simple fraction as a pair of integers. You can create a class for it (with some arithmetic methods) or start by using a simple array. It all depends on your needs.

Floating point multiplication in java [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to round a number to n decimal places in Java
When multiplying two numbers in java happens this:
double a = 9.495 * 100;
Expected result:
a = 949.5;
But the obtained result is:
a = 949.4999999999999
When I try to round number 9.495 in two decimal places the result is 9.49 instead of 9.50
Any ideas how to solve this problem?
If you want accurate floating point computations, do not use the float or double types, but rather make use of the BigDecimal class.
This is a side effect of floating point calculations, and is well understood, but not necessarily intuitive. This question has actually been asked literally thousands of times, and you need to study how floating point arithmetic works.
To get around this, if you only need 2-decimal precision, then use a integer instead.
For example, if you're dealing with currency, and you want to buy a 100 items for $4.95, then you represent the cost of that value as the integer "495", an multiply that by 100, which gives you "49500". You always treat the last two digits as cents, so "49500" is $495.00.
You cannot. Floating point and double precision numbers in a computer cannot represent all possible values.

Categories