mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-03-07 18:27:40 +08:00
bug #977: avoid division by 0 in normalize() and normalized().
This commit is contained in:
parent
7cae8918c0
commit
ee37eb4eed
@ -102,7 +102,10 @@ inline typename NumTraits<typename internal::traits<Derived>::Scalar>::Real Matr
|
|||||||
return numext::sqrt(squaredNorm());
|
return numext::sqrt(squaredNorm());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \returns an expression of the quotient of *this by its own norm.
|
/** \returns an expression of the quotient of \c *this by its own norm.
|
||||||
|
*
|
||||||
|
* \warning If the input vector is too small (i.e., this->norm()==0),
|
||||||
|
* then this function returns a copy of the input.
|
||||||
*
|
*
|
||||||
* \only_for_vectors
|
* \only_for_vectors
|
||||||
*
|
*
|
||||||
@ -114,19 +117,29 @@ MatrixBase<Derived>::normalized() const
|
|||||||
{
|
{
|
||||||
typedef typename internal::nested_eval<Derived,2>::type _Nested;
|
typedef typename internal::nested_eval<Derived,2>::type _Nested;
|
||||||
_Nested n(derived());
|
_Nested n(derived());
|
||||||
return n / n.norm();
|
RealScalar z = n.squaredNorm();
|
||||||
|
// NOTE: after extensive benchmarking, this conditional does not impact performance, at least on recent x86 CPU
|
||||||
|
if(z>RealScalar(0))
|
||||||
|
return n / numext::sqrt(z);
|
||||||
|
else
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Normalizes the vector, i.e. divides it by its own norm.
|
/** Normalizes the vector, i.e. divides it by its own norm.
|
||||||
*
|
*
|
||||||
* \only_for_vectors
|
* \only_for_vectors
|
||||||
*
|
*
|
||||||
|
* \warning If the input vector is too small (i.e., this->norm()==0), then \c *this is left unchanged.
|
||||||
|
*
|
||||||
* \sa norm(), normalized()
|
* \sa norm(), normalized()
|
||||||
*/
|
*/
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
inline void MatrixBase<Derived>::normalize()
|
inline void MatrixBase<Derived>::normalize()
|
||||||
{
|
{
|
||||||
*this /= norm();
|
RealScalar z = squaredNorm();
|
||||||
|
// NOTE: after extensive benchmarking, this conditional does not impact performance, at least on recent x86 CPU
|
||||||
|
if(z>RealScalar(0))
|
||||||
|
derived() /= numext::sqrt(z);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------- implementation of other norms ----------
|
//---------- implementation of other norms ----------
|
||||||
|
@ -42,6 +42,15 @@ template<> struct adjoint_specific<false> {
|
|||||||
VERIFY_IS_APPROX(v1, v1.norm() * v3);
|
VERIFY_IS_APPROX(v1, v1.norm() * v3);
|
||||||
VERIFY_IS_APPROX(v3, v1.normalized());
|
VERIFY_IS_APPROX(v3, v1.normalized());
|
||||||
VERIFY_IS_APPROX(v3.norm(), RealScalar(1));
|
VERIFY_IS_APPROX(v3.norm(), RealScalar(1));
|
||||||
|
|
||||||
|
// check null inputs
|
||||||
|
VERIFY_IS_APPROX((v1*0).normalized(), (v1*0));
|
||||||
|
RealScalar very_small = (std::numeric_limits<RealScalar>::min)();
|
||||||
|
VERIFY( (v1*very_small).norm() == 0 );
|
||||||
|
VERIFY_IS_APPROX((v1*very_small).normalized(), (v1*very_small));
|
||||||
|
v3 = v1*very_small;
|
||||||
|
v3.normalize();
|
||||||
|
VERIFY_IS_APPROX(v3, (v1*very_small));
|
||||||
|
|
||||||
// check compatibility of dot and adjoint
|
// check compatibility of dot and adjoint
|
||||||
ref = NumTraits<Scalar>::IsInteger ? 0 : (std::max)((std::max)(v1.norm(),v2.norm()),(std::max)((square * v2).norm(),(square.adjoint() * v1).norm()));
|
ref = NumTraits<Scalar>::IsInteger ? 0 : (std::max)((std::max)(v1.norm(),v2.norm()),(std::max)((square * v2).norm(),(square.adjoint() * v1).norm()));
|
||||||
|
Loading…
Reference in New Issue
Block a user