RaysonK
RaysonK

Reputation: 553

truncated doubles getting long decimals in for loop in java

I have two double values that are truncated to two decimal spots. Each one represents a spot on a radian circle, and they are either supposed to increment or decrement by 0.01 until they find a target value. Here's the code:

    BigDecimal negPath = new BigDecimal(roundAndConvert(pendA.getTheta()));
    BigDecimal posPath = new BigDecimal(roundAndConvert(pendA.getTheta()));
    BigDecimal target = new BigDecimal(roundAndConvert(pendB.getTheta()));
    for (negPath = negPath; ((negPath.doubleValue() > -0.01) && (!negPath.equals(target))); negPath = negPath.subtract(new BigDecimal(0.01))) {}
    for (posPath = posPath; ((posPath.doubleValue() < 6.29) && (!posPath.equals(target))); posPath = posPath.add(new BigDecimal(0.01))) {}

//here's the method that rounds the values

public double roundAndConvert(double value)
{
        double holder = (int)(value*100) / 100.0;
        if (holder < 0)
        {
            while (holder < -6.28) {holder += 6.28;}
            holder += 6.28;
        }
        else
        {
            while (holder > 6.28) {holder -= 6.28;}
        }
        return holder;
}

The problem that I'm having is that the two Path values are returning doubles with long decimals, like so:

pos = 6.299999999999944
neg = -0.01999999999996656

The values that they return aren't like this before the for loop, so I think it has to do with the increment/decrement.

EDIT: tried replacing the doubles with BigDecimals, but now the program is freezing at the for loops. I see the stringCache for the Path values, and they still have the long decimals.

EDIT: Another change to the coding, this time using all BigDecimal objects and equals in the for loops, but I'm still getting long decimals.

EDIT: finally worked with the coding shown. The accepted answerer explains what I was doing wrong. Here's the code that works:

    for (negPath = negPath; ((negPath.doubleValue() > -0.01) && (!negPath.equals(new BigDecimal((int)(target.doubleValue()*100)/100.0)))); negPath = negPath.subtract(new BigDecimal(0.01))) 
    {
        negPath = new BigDecimal((int)(negPath.doubleValue()*100)/100.0);
    }
    for (posPath = posPath; ((posPath.doubleValue() < 6.29) && (!posPath.equals(new BigDecimal((int)(target.doubleValue()*100)/100.0)))); posPath = posPath.add(new BigDecimal(0.01))) 
    {
        negPath = new BigDecimal((int)(negPath.doubleValue()*100)/100.0);
    }

Upvotes: 0

Views: 200

Answers (2)

A.H.
A.H.

Reputation: 66243

Your code:

for (negPath = negPath; 
      ((negPath.doubleValue() > -0.01) && (negPath.doubleValue() != target));
      negPath.subtract(new BigDecimal(0.01))) 
{}

I see two bad errors here. First:

negPath.subtract(new BigDecimal(0.01))

should be

negPath = negPath.subtract(new BigDecimal(0.01))

because a BigDecimal is immutable - each operation on them just creates a new one. This might be the case why your loop never terminates now - because the state does not change in each loop.

Second:

(negPath.doubleValue() != target)

Comparing doubles that way is a no-no, because intermediate rounding-errors are quite sure to happen and then this part of the condition is never true.

Rationale: Please read some basic documentation about floating point calculations - floats are not just numbers as you know them from mathematics, they must be treated with great care.

Upvotes: 3

Dawood ibn Kareem
Dawood ibn Kareem

Reputation: 79808

Use BigDecimal instead of double.

Upvotes: 0

Related Questions