Comparing values for decimal point accuracy
Looping through calculations, I need to determine when a BigDecimal is accurate to a specific value (that is, stop when the BigDecimal < 10^−5.). Simplified example:
BigDecimal bd =new BigDecimal("0.0474271");
do{
// various calculations to get a new value for bigdecimal, daft example is:
bd.add(new BigDecimal("0.00000000001"));
}while (?)
The condition for the do-while loop is: when bd is accurate to 10^-5 (having dusted off the old maths textbooks, apparently this is aka 1.0E-5 aka 0.00001 aka Math.pow(10.0, -5.0) ).
Having read through the API (very useful!) I've so far come up with the following solution for my while statement:
bd.compareTo (new BigDecimal("0.00001")) < 0
(Note that compareTo "returns: a negative number, zero, or a positive number if BigDecimal is numerically less than, equal to, or greater than 0".)
However, this stops at the second step in the loop... when I can plainly see from println step-statements that the BigDecimal still has a value very near to 0.0474271.
Can anyone point out what's going wrong here? Having read and reread my statements, looked through the logic, I just can't see for the life of me why this isn't working how it's supposed to (well, how I want it to... it's obviously my mistake because I don't think Java has "off" days lol).
Kate.
BigDecimal's compareTo method compares two BigDecimals, not whether they are within a certain range of each other.
From the api:
Returns: -1, 0, or 1 as this BigDecimal is numerically less than, equal to, or greater than val.
bd.compareTo (new BigDecimal("0.00001")) < 0
tells you if bd is less than .00001, not if it's within .00001 of some other number. If you want to determine if bd is within .00001 of, say, .0500000, then try subtracting bd from .050000, then comparing the result to .00001. If the difference is less than .00001, then you're within your tolerance. Hope I explained that well :).
You want to keep looping untill you're below a certain value, right? Then you just did it the other way around.
Try this demo:BigDecimal bd = new BigDecimal("0.0474271");
final BigDecimal TO_SUBTRACT = new BigDecimal("0.000001");
final BigDecimal STOP_BELOW = new BigDecimal("0.000001");
int numLoops = 0;
do {
numLoops++;
bd = bd.subtract(TO_SUBTRACT);
} while(bd.compareTo(STOP_BELOW) > 0); // <- This means: keep looping while 'bd' is larger than
//'STOP_BELOW', and stop when it's less than 'STOP_BELOW'
System.out.print("Subtracted "+TO_SUBTRACT+" "+numLoops+" times, ");
System.out.println("'bd' now is: "+bd.toPlainString());
Unless I misunderstand your requirements, why loop at all? As hunter9000 states, why not just subtract or add? Concrete example: I'd like to know if x lies around 6 (give or take 2). Would you write a loop for that? I bet not - you'd probably write something likeboolean liesWithin (int value) {
return ((value <= 6) && (value + 2 >= 6)) || ((value >= 6) && (value - 2 <= 6));
}
, or, more abstractboolean liesWithin(int value, int frontier, int tolerance) {
return ((value <= frontier) && (value + tolerance >= frontier)) || ((value >= frontier) && (value - tolerance <= frontier));
}
(Haven't really thought long about the argument names.)
If you have an iterative algorithm which is only accurate to a given tolerance, why are you using BigDecimal, which gives precise arithmetic? (There are cases where you want a tolerance finer than the precision of double for the magnitudes of the result, so they aren't totally exclusive, but it's not often that this happens)
If you don't know the value you are converging on, you can use the difference between the values of successive iterations; when that's a certain factor of the tolerance, the result of a well behaved algorithm will be within tolerance (determining the factor requires knowledge of the algorithm. Or you can guess at 0.5, which works for quadratics).
Conversely, if you do know the value you are converging on, then use that value ;o).
Pete