I got a little problem with a function I need in my java progam. I want to check the total amount of digits, a 'double' variable has. (e.g.: 5 should return 1, 5.0034 should return 5, and 2.04 should return 3.) My function is this:
private int getDoubleLength (double a) {
int len = 0;
while (a != (int) a) {
a *= 10;
}
while (a > 1) {
len ++;
a/=10;
}
System.out.println(String.format("Double %f has %d digits.",a,len));
return len;
}
Now this works perfectly, but when I am making some mathematical calculations, you get the slight errors of doubles: I divide 10 by cos(60), which is 0,5. The answer should be 20.0, but the program gives a 20.000000000000004 (that number, I copied it). My while loop gets stuck, and the program hangs.
Any ideas? (Or other great solutions for checking the digits of a number!)
Doubles and floats and operations on then are not exact so there will always bee slight errors compared with algebraic calculations. If you are using cosines etc then you will always have to deal with these rounding errors which any book or web text on numerical analysis should describe. If you are using simple aritmetic operations look at java.lang.BigDecimal
For details on how floating point values are stored.see What Every Computer Scientist Should Know About Floating-Point Arithmetic
toString().length() should solve it
remeber to substract the '.' if it is there and shouldn't be counted
This is how I implemented mine, Simple converting to String when the double was to big returned String with an exponential representation. i.e 20000000 would return 2.0E+7, and the split would then split it from here resulting in wrong count. I used to BigDecimal
and to toPlainString()
method
protected int countDecimalDigits(Double d) {
BigDecimal deci = BigDecimal.valueOf(d);
int integerPlaces = 0;
int decimalPlaces = 0;
String text = deci.toPlainString();
String[] integerDecimalSplit = text.split("\\.");
if (null != integerDecimalSplit[0]) {
integerPlaces = integerDecimalSplit[0].length();
}
if (integerDecimalSplit.length > 1) {
decimalPlaces = integerDecimalSplit[1].length();
}
return integerPlaces + decimalPlaces;
}
It's a rounding issue. I would use Strings, count the characters, and decide what figures are to be counted significant.