Why I get trailing so many numbers when I run below code?
BigDecimal lat = new BigDecimal(0.0077);
System.out.println(lat);
output >>
0.00770000000000000024702462297909733024425804615020751953125
I want to print exactly what I entered. How can I do this?
Most finite decimal fractions cannot be exactly represented by floating-point, so that is the approximation you get when you create the floating-point literal 0.0077.
To avoid the problem, use the constructor BigDecimal(String val) instead:
BigDecimal lat = new BigDecimal("0.0077");
As #TimB points out, if you already have a double value, you can also use:
BigDecimal lat = BigDecimal.valueOf(doubleVal);
Also, here is the mandatory reference to What Every Computer Scientist Should Know About Floating-Point Arithmetic.
When you have a number like 0.077 this cannot be exactly represented and in fact you get a number which is almost this, but with a small error. When you print this number as a string, the code to do this "knows" to discard the small error and you see the number you expect.
BigDecimal tries to give you a faithful representation and it is doing what it should even if this is surprising. What you want to use is the following method
BigDecimal bd = BigDecimal.valueOf(0.077);
In this case the BigDecimal takes the value as it would be printed, instead of the true value represented.
why is it so long?
To accurately represent a 53-bit fraction (double has a 53-bit mantissa) you need 53 decimal digits. e.g. every time you multiple by 10 to get another digit, you multiple 2 (and 5) which makes the lower bit 0 and eventually you guarentee to have all 0 bits and no more digits.
Try this:
System.out.println(String.format("%.4f",lat));
where 4 in %.4f specified how many decimal places you want to display
Note that this will only format your output display. the actual value of lat however still 0.00770000000000000024702462297909733024425804615020751953125
You can also use NumberFormat and specify the fraction digits setMinimumFractionDigits(4)
BigDecimal lat = new BigDecimal(0.0077);
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMinimumFractionDigits(4);
System.out.println(nf.format(lat));
BigDecimal lat = new BigDecimal(0.0077);
lat=lat.setScale(4,RoundingMode.HALF_EVEN);
System.out.println(lat);
Related
I am working with an application that is based entirely on doubles, and am having trouble in one utility method that parses a string into a double. I've found a fix where using BigDecimal for the conversion solves the issue, but raises another problem when I go to convert the BigDecimal back to a double: I'm losing several places of precision. For example:
import java.math.BigDecimal;
import java.text.DecimalFormat;
public class test {
public static void main(String [] args){
String num = "299792.457999999984";
BigDecimal val = new BigDecimal(num);
System.out.println("big decimal: " + val.toString());
DecimalFormat nf = new DecimalFormat("#.0000000000");
System.out.println("double: "+val.doubleValue());
System.out.println("double formatted: "+nf.format(val.doubleValue()));
}
}
This produces the following output:
$ java test
big decimal: 299792.457999999984
double: 299792.458
double formatted: 299792.4580000000
The formatted double demonstrates that it's lost the precision after the third place (the application requires those lower places of precision).
How can I get BigDecimal to preserve those additional places of precision?
Thanks!
Update after catching up on this post. Several people mention this is exceeding the precision of the double data type. Unless I'm reading this reference incorrectly:
http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.3
then the double primitive has a maximum exponential value of Emax = 2K-1-1, and the standard implementation has K=11. So, the max exponent should be 511, no?
You've reached the maximum precision for a double with that number. It can't be done. The value gets rounded up in this case. The conversion from BigDecimal is unrelated and the precision problem is the same either way. See this for example:
System.out.println(Double.parseDouble("299792.4579999984"));
System.out.println(Double.parseDouble("299792.45799999984"));
System.out.println(Double.parseDouble("299792.457999999984"));
Output is:
299792.4579999984
299792.45799999987
299792.458
For these cases double has more than 3 digits of precision after the decimal point. They just happen to be zeros for your number and that's the closest representation you can fit into a double. It's closer for it to round up in this case, so your 9's seem to disappear. If you try this:
System.out.println(Double.parseDouble("299792.457999999924"));
You'll notice that it keeps your 9's because it was closer to round down:
299792.4579999999
If you require that all of the digits in your number be preserved then you'll have to change your code that operates on double. You could use BigDecimal in place of them. If you need performance then you might want to explore BCD as an option, although I'm not aware of any libraries offhand.
In response to your update: the maximum exponent for a double-precision floating-point number is actually 1023. That's not your limiting factor here though. Your number exceeds the precision of the 52 fractional bits that represent the significand, see IEEE 754-1985.
Use this floating-point conversion to see your number in binary. The exponent is 18 since 262144 (2^18) is nearest. If you take the fractional bits and go up or down one in binary, you can see there's not enough precision to represent your number:
299792.457999999900 // 0010010011000100000111010100111111011111001110110101
299792.457999999984 // here's your number that doesn't fit into a double
299792.458000000000 // 0010010011000100000111010100111111011111001110110110
299792.458000000040 // 0010010011000100000111010100111111011111001110110111
The problem is that a double can hold 15 digits, while a BigDecimal can hold an arbitrary number. When you call toDouble(), it attempts to apply a rounding mode to remove the excess digits. However, since you have a lot of 9's in the output, that means that they keep getting rounded up to 0, with a carry to the next-highest digit.
To keep as much precision as you can, you need to change the BigDecimal's rounding mode so that it truncates:
BigDecimal bd1 = new BigDecimal("12345.1234599999998");
System.out.println(bd1.doubleValue());
BigDecimal bd2 = new BigDecimal("12345.1234599999998", new MathContext(15, RoundingMode.FLOOR));
System.out.println(bd2.doubleValue());
Only that many digits are printed so that, when parsing the string back to double, it will result in the exact same value.
Some detail can be found in the javadoc for Double#toString
How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument d. Then d must be the double value nearest to x; or if two double values are equally close to x, then d must be one of them and the least significant bit of the significand of d must be 0.
If it's entirely based on doubles ... why are you using BigDecimal? Wouldn't Double make more sense? If it's too large of value (or too much precision) for that then ... you can't convert it; that would be the reason to use BigDecimal in the first place.
As to why it's losing precision, from the javadoc
Converts this BigDecimal to a double. This conversion is similar to the narrowing primitive conversion from double to float as defined in the Java Language Specification: if this BigDecimal has too great a magnitude represent as a double, it will be converted to Double.NEGATIVE_INFINITY or Double.POSITIVE_INFINITY as appropriate. Note that even when the return value is finite, this conversion can lose information about the precision of the BigDecimal value.
You've hit the maximum possible precision for the double. If you would still like to store the value in primitives... one possible way is to store the part before the decimal point in a long
long l = 299792;
double d = 0.457999999984;
Since you are not using up (that's a bad choice of words) the precision for storing the decimal section, you can hold more digits of precision for the fractional component. This should be easy enough to do with some rounding etc..
I am trying to divide a 19 digit number by 100, i.e. 19 digit number/100, in java. It can be divisible using long data type but I'm not getting the full value as 17 digits and a decimal point followed by another 2 digits. Instead, I'm only getting 17 digits as it was a long data type so I need that digit like mathematical expression.
long cardValue = ("1234567891234567891");
long divide = (cardValue/100);
System.out.println(divide);
Output: 12345678912345678
I need output as 12345678912345678.91
longs are large integers, and when you divide one by another you use integer division, which omits everything right of the decimal point.
You could use a BigDecimal instead:
BigDecimal divide = new BigDecimal(String.valueOf(cardValue)).divide(new BigDecimal(100));
Firstly, you are doing integer division, and then expecting a decimal value. In Java, 1234 / 10 results in 123, and not 123.4. If you want a decimal result, make one of the values decimal, i.e., 1234.0 / 10 or 1234 / 10.0. This will yield 123.4
As of your problem, since the number is very large, using BigDecimal is a better idea (not BigInteger, as it will again perform integer division, while you want a decimal result). So, try
BigDecimal b = new BigDecimal("1234567891234567891");
BigDecimal res = b.divide(new BigDecimal("100"));
Or you can do a one-liner as
new BigDecimal("1234567891234567891").divide(new BigDecimal("100"))
In first, res = 12345678912345678.91, and the other will also result in the same.
Note : Although BigInteger and BigDecimal are all included in java.math package, but if it raises an error, import it by using
import java.math.BigDecimal;
Integer and long don't have decimal point.
Instead, use double.
double a = 123456789.00
double answer = (a/100.00)
Refer primitive data types in java.
If you want to get the string and want to dive, then use parseDouble() method to convert it to double. After this step perform division.
The divide variable is long type, that means no decimal fractions, just integer values. If you use double, you can obtain decimals, but that type don't have the precision you need in this case because it gives up to 15 significant numbers.
Your only solution is to use BigDecimal class. You can obtain whatever digit numbers you want. We used it for Banks and accounting applications, and is easy to understand how to work with it.
HTH
I have below logic that rounds a double value to 2 decimal places:
public double round(double value, int places) {
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
It is working for most of the cases but fails to round the result to 2 decimal places in some cases, below is an example for it.
If I call this method using code round(12.503, 2), I need the result as 12.50 because I need result in 2 decimal places, but I am getting output as 12.5
Please help me how to fix this case.
A double in Java represents a mathematical number where 12.50 is the same number as 12.5. How many digits of a number are shown is a concern of converting it to a string, not of the number itself.
So better do the rounding when you convert the number to a string for output, e.g.:
System.out.printf("%5.2f", value);
You are not getting the result as 12.5.
You are receiving back a double.
Then, you have chosen some arbitrary method of displaying that double, (which you have told us nothing about,) and based on the results of applying that method you think that its value is 12.5.
You see, the thing with doubles is that they cannot be thought of as having a fixed number of decimal digits. (Or, more accurately, the number of decimal digits that they have is so huge, that nobody ever wants to see them all.) So, in all likelihood the actual value of the double that you receive, without any bias introduced by various methods of displaying it, is something akin to 12.5000000... But you need to choose the right method of displaying it in order to see what it is. If the method that you chose simply strips trailing zeros, then you may be left with the impression that you are missing a trailing zero. Or 10 trailing zeros.
So, you need to convert it back to BigDecimal before you can make any assumptions as to what result you are getting.
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.
I am working with an application that is based entirely on doubles, and am having trouble in one utility method that parses a string into a double. I've found a fix where using BigDecimal for the conversion solves the issue, but raises another problem when I go to convert the BigDecimal back to a double: I'm losing several places of precision. For example:
import java.math.BigDecimal;
import java.text.DecimalFormat;
public class test {
public static void main(String [] args){
String num = "299792.457999999984";
BigDecimal val = new BigDecimal(num);
System.out.println("big decimal: " + val.toString());
DecimalFormat nf = new DecimalFormat("#.0000000000");
System.out.println("double: "+val.doubleValue());
System.out.println("double formatted: "+nf.format(val.doubleValue()));
}
}
This produces the following output:
$ java test
big decimal: 299792.457999999984
double: 299792.458
double formatted: 299792.4580000000
The formatted double demonstrates that it's lost the precision after the third place (the application requires those lower places of precision).
How can I get BigDecimal to preserve those additional places of precision?
Thanks!
Update after catching up on this post. Several people mention this is exceeding the precision of the double data type. Unless I'm reading this reference incorrectly:
http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.3
then the double primitive has a maximum exponential value of Emax = 2K-1-1, and the standard implementation has K=11. So, the max exponent should be 511, no?
You've reached the maximum precision for a double with that number. It can't be done. The value gets rounded up in this case. The conversion from BigDecimal is unrelated and the precision problem is the same either way. See this for example:
System.out.println(Double.parseDouble("299792.4579999984"));
System.out.println(Double.parseDouble("299792.45799999984"));
System.out.println(Double.parseDouble("299792.457999999984"));
Output is:
299792.4579999984
299792.45799999987
299792.458
For these cases double has more than 3 digits of precision after the decimal point. They just happen to be zeros for your number and that's the closest representation you can fit into a double. It's closer for it to round up in this case, so your 9's seem to disappear. If you try this:
System.out.println(Double.parseDouble("299792.457999999924"));
You'll notice that it keeps your 9's because it was closer to round down:
299792.4579999999
If you require that all of the digits in your number be preserved then you'll have to change your code that operates on double. You could use BigDecimal in place of them. If you need performance then you might want to explore BCD as an option, although I'm not aware of any libraries offhand.
In response to your update: the maximum exponent for a double-precision floating-point number is actually 1023. That's not your limiting factor here though. Your number exceeds the precision of the 52 fractional bits that represent the significand, see IEEE 754-1985.
Use this floating-point conversion to see your number in binary. The exponent is 18 since 262144 (2^18) is nearest. If you take the fractional bits and go up or down one in binary, you can see there's not enough precision to represent your number:
299792.457999999900 // 0010010011000100000111010100111111011111001110110101
299792.457999999984 // here's your number that doesn't fit into a double
299792.458000000000 // 0010010011000100000111010100111111011111001110110110
299792.458000000040 // 0010010011000100000111010100111111011111001110110111
The problem is that a double can hold 15 digits, while a BigDecimal can hold an arbitrary number. When you call toDouble(), it attempts to apply a rounding mode to remove the excess digits. However, since you have a lot of 9's in the output, that means that they keep getting rounded up to 0, with a carry to the next-highest digit.
To keep as much precision as you can, you need to change the BigDecimal's rounding mode so that it truncates:
BigDecimal bd1 = new BigDecimal("12345.1234599999998");
System.out.println(bd1.doubleValue());
BigDecimal bd2 = new BigDecimal("12345.1234599999998", new MathContext(15, RoundingMode.FLOOR));
System.out.println(bd2.doubleValue());
Only that many digits are printed so that, when parsing the string back to double, it will result in the exact same value.
Some detail can be found in the javadoc for Double#toString
How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument d. Then d must be the double value nearest to x; or if two double values are equally close to x, then d must be one of them and the least significant bit of the significand of d must be 0.
If it's entirely based on doubles ... why are you using BigDecimal? Wouldn't Double make more sense? If it's too large of value (or too much precision) for that then ... you can't convert it; that would be the reason to use BigDecimal in the first place.
As to why it's losing precision, from the javadoc
Converts this BigDecimal to a double. This conversion is similar to the narrowing primitive conversion from double to float as defined in the Java Language Specification: if this BigDecimal has too great a magnitude represent as a double, it will be converted to Double.NEGATIVE_INFINITY or Double.POSITIVE_INFINITY as appropriate. Note that even when the return value is finite, this conversion can lose information about the precision of the BigDecimal value.
You've hit the maximum possible precision for the double. If you would still like to store the value in primitives... one possible way is to store the part before the decimal point in a long
long l = 299792;
double d = 0.457999999984;
Since you are not using up (that's a bad choice of words) the precision for storing the decimal section, you can hold more digits of precision for the fractional component. This should be easy enough to do with some rounding etc..