Normalized double vector, not unit length to machine accuracy

I have a Java application that uses arrogant vectors formed from double. It normalizes these vectors by multiplying the components of the vector by the inverse of the Euclidean norm. Sometimes the resulting vector has a norm that is not equal to 1 for machine accuracy. The fact that this is happening does not surprise me.

My question is: how to normalize a vector so that the resulting vector has a unit of length for the accuracy of the machine?

These are the methods for my Vector class to calculate the norm and normalize the vector:

public double getFrobeniusNorm() {
    return Math.sqrt(getFrobeniusNormSquared());
}

public double getFrobeniusNormSquared() {
    double normSquared = 0.0;
    int numberOfRows = getRowDimension();
    int numberOfColumns = getColumnDimension();
    for(int i = 0; i < numberOfRows; ++i) {
        for(int j = 0; j < numberOfColumns; ++j) {
            double matrixElement = get(i,j);
            normSquared += matrixElement*matrixElement;
        }
    }
    return normSquared;
}

public void normalize() {
    double norm = getFrobeniusNorm();
    if (norm == 0) {
        throw new ArithmeticException("Cannot get a unit vector from the zero vector.");            
    } else {
        double oneOverNorm = 1.0 / norm;
        multiplyEquals(oneOverNorm);
    }
}

Since this is Java, I cannot use methods specific to the operating system and processor, but otherwise it looks like a standard floating point algorithm.

/ , . , , , , . .

, u. u.normalize(). , Math.abs(u.getFrobeniusNorm()-1d, ulps. . , . , , u.getFrobeniusNorm(), 1 ulps. u.getFrobeniusNorm() , , .

+1
5

, . Kahan Summation. , .

:

  • x. x.
  • x 1/x. u.
  • u. u. u 1 .

, , , , , . , , ~ *. , . , , .

, , . , ( ) 1, . " ", , , , , , ( 1). , , , , 2.

, . , , .

, .

0

: - , - , - .

1.0, ( ).

, , ( , - - ).

: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html ( )

+1

, , . (, , .) , "" , , .

, , , , 1, n * epsilon 1. , , , .

( : " , 1, . , ( )." , .)

+1

, . , sqrt() , getFrobeniusNormSquared(). , , . , , sqrt():

double norm = X * X + Y * Y + Z * Z;
if (norm > 0.0)
{
  norm = 1.0 / norm;
  return new vector
  {
      X = Math.Sign(X) * Math.Sqrt(X * X * norm),
      Y = Math.Sign(Y) * Math.Sqrt(Y * Y * norm),
      Z = Math.Sign(Z) * Math.Sqrt(Z * Z * norm),
  };
}
else
    throw new ArithmeticException("Cannot get a unit vector from the zero vector.");

, , - , .

+1

, . :

, 1 d ( ). , 1.

, e x. , arccos ((1 + xe)/sqrt (1 + 2 xe + e 2)), , , . x; x ( ) x). e , . , (x + e) 2 - x 2= 2 < > > + 2. e , , e , x. x. , "-" .

, , .

: , , . ?

Another consideration is that the change we can make to the elements is quantized, so instead of changing e to a larger element, we might prefer changing e / 2 to a smaller element if it changes the calculated norm by the same amount.
0
source

All Articles