标准化的双矢量不单位长度到机器的精度 [英] Normalized Double Vector Not Unit Length To Machine Precision
问题描述
我的问题是:我如何规格化矢量,使得生成的矢量具有单位长度来加工精度? b
$ b
这些是我的Vector类来计算规范和规格化向量的方法: 我可以改进使用卡农求和和/或划分的范数计算最大的组成部分,但规范化和计算规范之间的一致性是真正的问题。范数比方向更重要,所以我认为这是为了找到与原始矢量方向最接近的浮点向量,并且规范为1,以加工精度。对于我的目的,原始矢量是确切的。 假设原始矢量是 u 。我调用 标准化方法包含三个步骤: I have a Java application that uses high-dimensional vectors formed from double's. It normalizes these vectors by multiplying the vector components by the reciprocal of the Euclidean norm. Sometimes, the resulting vector has a norm that is not equal to 1 to machine-precision. That this occurs does not surprise me. My question is: how do I normalize the vector such that the resulting vector has unit length to machine precision? These are the methods for my Vector class to compute the norm and normalize the vector: Since this is Java, I can't use techniques specific to the operating system and processor, but otherwise this seems like a standard floating-point algorithm issue. I can improve the norm calculation using Kahan summation and/or dividing out the largest component, but the consistency between normalizing and calculating the norm is the real issue. The norm is more important than the direction, so I see this as finding the floating point vector closest in direction to the original vector with the constraint that the norm is 1 to machine precision. For my purposes, the original vector is exact. Suppose the original vector is u. I call While the original question remains interesting, recently I found the source of the problem in my code. In another code, I was improving a summation by implementing a variation of Kahan Summation. I revisited the unit vector code and found that the normalization was not the problem. The normalization method involves three steps: To improve the normalization method, I calculated the norm with the improved summation, scaled the components by the reciprocal of the more accurate norm, and calculated the norm of the unit vector using the improved summation to check how well it was normalized. Sure enough, the unit vector was normalized to a much lower tolerance which was ~ machine precision * dimension. I compared the improved normalization method to previous method, and it was better. What surprised me was that the old normalization method was just as accurate if the second vector norm calculation used the improved summation. So it was not the normalization itself that caused the problem, but rather the check of the normalization. It appears that naive summation is less accurate (even in a relative sense) for sums near 1 than for many other values. I say "many other values" the original problem occurred for vectors of all magnitudes in practice, but I suspect that some vectors, and therefore some sums, have the same bad behavior as unit vectors (with sums near 1). However, the problem norm values are probably sparsely distributed over the real numbers, like powers of 2. In the original method, the problem was that the two vector norm calculations had different relative accuracies. If you start with a vector with a norm near one, the two calculations would have nearly identical relative accuracies, and the normalization itself would be inaccurate. So now, I don't calculate the vector norm of the unit vector as a check. 这篇关于标准化的双矢量不单位长度到机器的精度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
$ p $ 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;
$ b $ public void normalize(){
double norm = getFrobeniusNorm();
if(norm == 0){
throw new ArithmeticException(无法从零向量获取单位向量);
} else {
double oneOverNorm = 1.0 / norm;
multiplyEquals(oneOverNorm);
$因为这是Java,所以我不能使用技巧具体到操作系统和处理器,否则这似乎是一个标准的浮点算法问题。
u.normalize()
。然后,如果我计算 Math.abs(u.getFrobeniusNorm() - 1d
,在某些情况下,结果是几百个ulps,这是我的问题。向量范数有错误,我只想对向量进行归一化,使得由 u.getFrobeniusNorm()
计算的范数是1到最小可能的ulps。改善 u.getFrobeniusNorm()
是有道理的,但是我认为这不能解决一致性问题。
现在,我不知道不要计算单位向量的向量范数作为检查。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);
}
}
u.normalize()
. Then, if I compute Math.abs(u.getFrobeniusNorm()-1d
, in some cases, the result is hundreds of ulps. This is the problem. I can accept that the vector norm has error. I just want to normalize the vector such that the norm as calculated by u.getFrobeniusNorm()
is 1 to the smallest possible ulps. Improving u.getFrobeniusNorm()
makes sense, but I don't think that solves the consistency issue.