aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Gael Guennebaud <g.gael@free.fr>2014-09-10 23:11:58 +0200
committerGravatar Gael Guennebaud <g.gael@free.fr>2014-09-10 23:11:58 +0200
commit5e890d3ad78a7e5c491a43202993d617fffb964a (patch)
treeb6a6a1fd95b555334f713ae314ebc46177d6e6a1
parent2d90484450f3934db3f5db39ef37967fb9444263 (diff)
Improve further the accuracy of JacobiSVD wrt under/overflow while improving speed for small matrices (hypot is very slow).
-rw-r--r--Eigen/src/SVD/JacobiSVD.h17
-rw-r--r--test/jacobisvd.cpp29
2 files changed, 35 insertions, 11 deletions
diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h
index 6ff689de3..3ab8a4c8a 100644
--- a/Eigen/src/SVD/JacobiSVD.h
+++ b/Eigen/src/SVD/JacobiSVD.h
@@ -425,18 +425,19 @@ void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q,
JacobiRotation<RealScalar> rot1;
RealScalar t = m.coeff(0,0) + m.coeff(1,1);
RealScalar d = m.coeff(1,0) - m.coeff(0,1);
- if(t == RealScalar(0))
+
+ if(d == RealScalar(0))
{
- rot1.c() = RealScalar(0);
- rot1.s() = d > RealScalar(0) ? RealScalar(1) : RealScalar(-1);
+ rot1.s() = RealScalar(0);
+ rot1.c() = RealScalar(1);
}
else
{
- RealScalar t2d2 = numext::hypot(t,d);
- rot1.c() = abs(t)/t2d2;
- rot1.s() = d/t2d2;
- if(t<RealScalar(0))
- rot1.s() = -rot1.s();
+ // If d!=0, then t/d cannot overflow because the magnitude of the
+ // entries forming d are not too small compared to the ones forming t.
+ RealScalar u = t / d;
+ rot1.s() = RealScalar(1) / sqrt(RealScalar(1) + numext::abs2(u));
+ rot1.c() = rot1.s() * u;
}
m.applyOnTheLeft(0,1,rot1);
j_right->makeJacobi(m,0,1);
diff --git a/test/jacobisvd.cpp b/test/jacobisvd.cpp
index 7dbb29c59..cd04db5be 100644
--- a/test/jacobisvd.cpp
+++ b/test/jacobisvd.cpp
@@ -354,11 +354,33 @@ void jacobisvd_underoverflow()
Matrix2d M;
M << -7.90884e-313, -4.94e-324,
0, 5.60844e-313;
+ JacobiSVD<Matrix2d> svd;
+ svd.compute(M,ComputeFullU|ComputeFullV);
+ jacobisvd_check_full(M,svd);
+
+ VectorXd value_set(9);
+ value_set << 0, 1, -1, 5.60844e-313, -5.60844e-313, 4.94e-324, -4.94e-324, -4.94e-223, 4.94e-223;
+ Array4i id(0,0,0,0);
+ int k = 0;
+ do
+ {
+ M << value_set(id(0)), value_set(id(1)), value_set(id(2)), value_set(id(3));
+ svd.compute(M,ComputeFullU|ComputeFullV);
+ jacobisvd_check_full(M,svd);
+
+ id(k)++;
+ if(id(k)>=value_set.size())
+ {
+ while(k<3 && id(k)>=value_set.size()) id(++k)++;
+ id.head(k).setZero();
+ k=0;
+ }
+
+ } while((id<int(value_set.size())).all());
+
#if defined __INTEL_COMPILER
#pragma warning pop
#endif
- JacobiSVD<Matrix2d> svd;
- svd.compute(M); // just check we don't loop indefinitely
// Check for overflow:
Matrix3d M3;
@@ -367,7 +389,8 @@ void jacobisvd_underoverflow()
-8.7190887618028355e+307, -7.3453213709232193e+307, -2.4367363684472105e+307;
JacobiSVD<Matrix3d> svd3;
- svd3.compute(M3); // just check we don't loop indefinitely
+ svd3.compute(M3,ComputeFullU|ComputeFullV); // just check we don't loop indefinitely
+ jacobisvd_check_full(M3,svd3);
}
void jacobisvd_preallocate()