我在MATLAB中实现了Forbenius规范的以下定义 https://puu.sh/xXsJZ/c42a5e9eac.png
以它描述的方式(即我做了2个循环,并通过平方每个元素增加了一个总和,最后我拿了总和的平方根)。
我的问题是,有没有办法实现这个规范,这样如果我在矩阵中输入一个相当大的数字,它的方块不会溢出?在某些情况下,该函数返回“Infinity”,即使真正的Forbenius规范可能远低于机器的溢出阈值。 (回想一下,在计算结束时取平方根。)
编辑:还存在下溢问题。即使元素ai,j不是太小,其正方形也可能下溢。在MATLAB中,一个 下溢的元素设置为0.现在只要其他一些元素很大 够了,结果仍然可以接受。另一方面,如果所有元素都下溢,我的函数可能会错误地返回0。
任何帮助?
在我的机器上产生无穷大的矩阵的一个例子是
[1,9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999; 1,1]
然而,当我使用内置的Frobenius规范函数时,它可以正常工作。为什么会这样?
答案 0 :(得分:1)
以下代码虽然在Java中,但与Matlab在计算Frobenius规范时所做的工作非常接近。这里的诀窍是hypot
函数,而不是仅仅执行x^2 + y^2
,它计算斜边以避免欠流/过流。 hypot
在matlab中可用,所以不要计算sqrt(x^2 + y^2)
,而是使用hypot,你应该能够避免欠流/过流。
public static double normFrob(double[][] matrix) {
double norm = 0.0;
int rows = matrix.length;
int cols = matrix[0].length;
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
norm = hypot(norm, matrix[i][j]);
}
}
return norm;
}
public static double hypot(double a, double b) {
double r;
if (Math.abs(a) > Math.abs(b)) {
r = b / a;
r = Math.abs(a) * Math.sqrt(1 + r * r);
} else if (b != 0) {
r = a / b;
r = Math.abs(b) * Math.sqrt(1 + r * r);
} else {
r = 0.0;
}
return r;
}
此代码片段取自Jama,这是为了向Matrix引入Matrix库,而一些开发人员是Matlab人员。
答案 1 :(得分:0)
溢出保护可以通过各种方式完成。一种可能性是正常化。这是欧几里德规范,但想法是一样的
m_sum = 0;
y=max(abs(x));
for i=1:len(x)
m_sum = m_sum + (x(i)/y)^2;
end
mynorm = y*sqrt(m_sum);