mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-03-07 18:27:40 +08:00
Rewrite balancer to avoid overflows.
The previous balancer overflowed for large row/column norms. Modified to prevent that. Fixes #2273.
This commit is contained in:
parent
35a367d557
commit
e9ab4278b7
@ -20,12 +20,6 @@ namespace internal {
|
|||||||
|
|
||||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T radix(){ return 2; }
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T radix2(){ return radix<T>()*radix<T>(); }
|
|
||||||
|
|
||||||
template<int Size>
|
template<int Size>
|
||||||
struct decrement_if_fixed_size
|
struct decrement_if_fixed_size
|
||||||
{
|
{
|
||||||
@ -141,7 +135,10 @@ inline
|
|||||||
bool companion<_Scalar,_Deg>::balanced( RealScalar colNorm, RealScalar rowNorm,
|
bool companion<_Scalar,_Deg>::balanced( RealScalar colNorm, RealScalar rowNorm,
|
||||||
bool& isBalanced, RealScalar& colB, RealScalar& rowB )
|
bool& isBalanced, RealScalar& colB, RealScalar& rowB )
|
||||||
{
|
{
|
||||||
if( RealScalar(0) == colNorm || RealScalar(0) == rowNorm ){ return true; }
|
if( RealScalar(0) == colNorm || RealScalar(0) == rowNorm
|
||||||
|
|| !(numext::isfinite)(colNorm) || !(numext::isfinite)(rowNorm)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//To find the balancing coefficients, if the radix is 2,
|
//To find the balancing coefficients, if the radix is 2,
|
||||||
@ -149,33 +146,41 @@ bool companion<_Scalar,_Deg>::balanced( RealScalar colNorm, RealScalar rowNorm,
|
|||||||
// \f$ 2^{2\sigma-1} < rowNorm / colNorm \le 2^{2\sigma+1} \f$
|
// \f$ 2^{2\sigma-1} < rowNorm / colNorm \le 2^{2\sigma+1} \f$
|
||||||
// then the balancing coefficient for the row is \f$ 1/2^{\sigma} \f$
|
// then the balancing coefficient for the row is \f$ 1/2^{\sigma} \f$
|
||||||
// and the balancing coefficient for the column is \f$ 2^{\sigma} \f$
|
// and the balancing coefficient for the column is \f$ 2^{\sigma} \f$
|
||||||
rowB = rowNorm / radix<RealScalar>();
|
const RealScalar radix = RealScalar(2);
|
||||||
|
const RealScalar radix2 = RealScalar(4);
|
||||||
|
|
||||||
|
rowB = rowNorm / radix;
|
||||||
colB = RealScalar(1);
|
colB = RealScalar(1);
|
||||||
const RealScalar s = colNorm + rowNorm;
|
const RealScalar s = colNorm + rowNorm;
|
||||||
|
|
||||||
while (colNorm < rowB)
|
// Find sigma s.t. rowNorm / 2 <= 2^(2*sigma) * colNorm
|
||||||
|
RealScalar scout = colNorm;
|
||||||
|
while (scout < rowB)
|
||||||
{
|
{
|
||||||
colB *= radix<RealScalar>();
|
colB *= radix;
|
||||||
colNorm *= radix2<RealScalar>();
|
scout *= radix2;
|
||||||
}
|
}
|
||||||
|
|
||||||
rowB = rowNorm * radix<RealScalar>();
|
// We now have an upper-bound for sigma, try to lower it.
|
||||||
|
// Find sigma s.t. 2^(2*sigma) * colNorm / 2 < rowNorm
|
||||||
while (colNorm >= rowB)
|
scout = colNorm * (colB / radix) * colB; // Avoid overflow.
|
||||||
|
while (scout >= rowNorm)
|
||||||
{
|
{
|
||||||
colB /= radix<RealScalar>();
|
colB /= radix;
|
||||||
colNorm /= radix2<RealScalar>();
|
scout /= radix2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//This line is used to avoid insubstantial balancing
|
// This line is used to avoid insubstantial balancing.
|
||||||
if ((rowNorm + colNorm) < RealScalar(0.95) * s * colB)
|
if ((rowNorm + radix * scout) < RealScalar(0.95) * s * colB)
|
||||||
{
|
{
|
||||||
isBalanced = false;
|
isBalanced = false;
|
||||||
rowB = RealScalar(1) / colB;
|
rowB = RealScalar(1) / colB;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
return true; }
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user