
-----------------------------------
Aziz
Fri Jun 29, 2007 3:21 pm

Floating point operation accuracy
-----------------------------------
Good afternoon folks. Been a while since I've posted. Anyways, doing some programming and ran into a strange occurrence. I'm making a Vector class to represent geometrical Vectors. I've developed an algorithm to determine the angles between two vectors, and it works for most values, however I get some weird values, that are off by a very small fraction (~E-6).

For example:

The angle between (1,0) and (0,1) comes out to exactly 90.

Between (1,1) and (1,0) is 45.00000000000001 (it should be exactly 45)

And between (1, 1) and (1, 1) is 1.2074182697257333E-6 and should really be 0 (there is no angle between parallel vectors)

I'm using the analytical formula 


	 * let v and u be vectors of the same dimension
	 * 
	 * let |v| and |u| represent the magnitudes of v and u, respectively
	 * 
	 * let A represent the angle between v and u
	 * 
	 *          v @ u            where @ represents dot product
	 * cos A = -------
	 *         |v|*|u|


I'll post my source code if you want to look at that.

I know this has something to do with the roundoff/precision errors of floating point, but I'm not sure if I should find a way around this, or leave it.

-----------------------------------
DIIST
Fri Jun 29, 2007 4:54 pm

Re: Floating point operation accuracy
-----------------------------------
What language? I know Java has a issues with floating point numbers. Post the code it might help.

-----------------------------------
md
Fri Jun 29, 2007 7:21 pm

RE:Floating point operation accuracy
-----------------------------------
It doesn't matter the language; it's actually quite clear what the problem is. Read http://en.wikipedia.org/wiki/Floating_point (see the accuracy section).

The solution would be to incorporate some error checking code. If you know that the answer is really small, then you can safely assume it's 0. Likewise 45.00000000000001 is really close to 45.00 so you know it should be 45.00. Unfortunately that's only really possible for specific cases, fortunately it's only really needed in specific cases. 0, 90, 180, 270. The rest of the angles would have errors so small as to be un-noticeable. 

The other solution which would make the errors smaller is to use doubles... but they are twice as large and perhaps not as fast.

-----------------------------------
wtd
Fri Jun 29, 2007 7:38 pm

RE:Floating point operation accuracy
-----------------------------------
Use true fractional types to get accuracy.

-----------------------------------
Aziz
Tue Jul 03, 2007 3:04 pm

RE:Floating point operation accuracy
-----------------------------------
That is correct, I am using Java, and I am using doubles.

Yeah, I knew it was the accuracy of floating-point values. Big Java and Big C++ by Cay Horstmann have 2 issues with that. A certain number cannot be represented in binary, just as 1/3 can't be represented in decimal.

I may include a function that returns a Fraction object, as well, however the double-returning function will still be needed. Anyways, so you guys believe I should create special cases for certain cardinal angles, each 45 degrees, perhaps? Just test if its within a close-enough range to one of these values (Within E, 10-14?).

But this leads me to a question? How do calculators get the precise answers (specifically when dealing with trigonometric functions)? Even the Windows calculator....

Here's the source: (disregard the UnitVector class, it's a stub). I've also included the source files a bytecode

The command-line for Vector is:

cmd d {v_1 
/*
 * Vector.java
 *
 * Created on June 26, 2007, 3:01 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package org.aaziz.math.geom;

import java.util.Arrays;
import java.text.NumberFormat;

import java.util.Random;
import java.util.List;

/**
 * Represents a geometric vector.
 *
 * 
 * This class is abstract because certain methods (such as multiplication)
 * are different for vectors of different dimension
 * 
 *
 * 
 * e.g. for 3-dimensionsal vectors there is a 'dot' product and a 'cross'
 * product, while 2-dimensional vectors only have the 'dot' product operation.
 * 
 *
 * 
 * A vector {@code v} could be represented as {@code v = (a,b)}. In that case,
 * the vector has 2 dimensions, such as {@code x} and {@code y} in a
 * Cartesian plane.
 * 
 *
 * 
 * The component {@code a} would be the component of the first dimension,
 * {@code x} for example. Likewise, {@code b} would be the component of the
 * second dimension, {@code y} for example.
 * 
 *
 * 
 * So, for {@code v}, {@code |v|} represents the magnitude of the vector. That
 * is, {@code |v|} is the length of the vector. The square of the magnitude
 * is equal to the square of each component, summed.
 * 
 *
 * 
 * Subclasses that define a fixed dimension should override the constructor
 * {@link #Vector(int)} to forbid the client to set a different number
 * of dimensions other than intended.
 * 
 *
 * @author ANTHONYA
 */;
 public class Vector implements Dimensional
 {
	 /**
	  * The components of this vector
	  */
	 private double

InvalidDimensionException.java

/*
 * InvalidDimensionException.java
 * 
 * Created on 27-Jun-2007, 11:04:17 AM
 * 
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.aaziz.math.geom;

/**
 * Thrown when a client tries to perform an operation on a {@link Dimensional}
 * involving an invalid dimension.
 * 
 * 
 * An invalid dimension could be:
 * 
 *		Dimensions less than zero
 *		Dimension greater than the number of dimensions of the object
 *		Dimension is not valid in other way (eg. not accessable)
 * 
 * 
 *
 * @author ANTHONYA
 */
public class InvalidDimensionException extends RuntimeException
{
	private int dimension = 0;
	
	/**
	 * Constructs a InvalidDimensionException with a general
	 * error message.
	 */
	public InvalidDimensionException()
	{
		super("Invalid dimension");
	}
	
	/**
	 * Constructs a InvalidDimensionException with a specified
	 * error message.
	 * @param message message of exception
	 */
	public InvalidDimensionException(String message)
	{
		super(message);
	}
		
    /**
	 * Constructs a InvalidDimensionException with the specifed
	 * dimension number that is invalid or caused the exception.
	 * 
	 * @param dimension the dimension that is the cause of the issue.
	 */
	public InvalidDimensionException(int dimension)
	{
		super("Invalid dimension: " + dimension);
		
		this.dimension = dimension;
	}

    /**
	 * Constructs a InvalidDimensionException with the specifed
	 * dimension number that is invalid or caused the exception and optional
	 * exception that was raised while performing the operation.
	 * 
	 * @param dimension the dimension that is the cause of the issue
     * @param cause exception that was raised while performing the operation
	 */
	public InvalidDimensionException(int dimension, Throwable cause)
	{
		super("Invalid dimension: " + dimension, cause);
		
		this.dimension = dimension;
	}

	/**
	 * Get the dimension that that is invalid or otherwised caused this
	 * exception
	 * 
	 * @return dimension number that caused this exception
	 */
    public int getDimension()
	{
        return dimension;
    }
	
	
}


Dimensional.java

/*
 * Dimensional.java
 * 
 * Created on 27-Jun-2007, 12:03:40 PM
 * 
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.aaziz.math.geom;

/**
 * This class represents a object that has dimensions.
 * 
 * This could be a geometric vector, line, plane, etc.
 * 
 * @see InvalidDimensionException
 * 
 * @author ANTHONYA
 */
public interface Dimensional
{
	/**
	 * Returns the number of dimensions this Dimensional has.
	 * 
	 * @return the number of dimensions
	 */
	public int getDimensions();
}



UnitVector.java

/*
 * UnitVector.java
 * 
 * Created on 29-Jun-2007, 4:24:21 PM
 * 
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.aaziz.math.geom;

/**
 *
 * @author ANTHONYA
 */
public class UnitVector extends Vector implements Dimensional
{
	public UnitVector(Vector v)
	{
		super(v);//todo
    }

}
