>

System.Windows.Media에서 Matrix를 사용하려고하는데 이해할 수없는 한계를 발견했습니다.

사례 1 :

double m11 = 0.0000001, // 1E-07
    m12 = 0,
    m21 = 0,
    m22 = 0.0000001; // 1E-07
var mat = new Matrix(m11, m12, m21, m22, 0, 0);
var det = mat.Determinant; // det = 9.9999999999999988E-15 <==> m11*m22-m12*m21 = 1E-07 * 1E-07 = 1E-14
if (mat.HasInverse) // true
    mat.Invert(); // OK

이 첫 번째 사례에서 우리는 모두 좋은 것 같습니다!

사례 2 :

double m11 = 0.00000001, // 1E-08
    m12 = 0,
    m21 = 0,
    m22 = 0.0000001; // 1E-07
var mat = new Matrix(m11, m12, m21, m22, 0, 0);
var det = mat.Determinant; // det = 9.9999999999999988E-16 <==> m11*m22-m12*m21 = 1E-08 * 1E-07 = 1E-15
if (mat.HasInverse) // false
    mat.Invert(); // KO : System.InvalidOperationException: 'Transform is not invertible.'

그러나이 두 번째 경우에는 행렬이 정사각형이고 행렬식이 0과 다른지 확인하지만 HasInverse는 false이고 Invert는 예외를 throw 할 수 있습니다. 내가 볼 수있는 유일한 차이점은 계산 1E-15 동안 필요한 정밀도입니다. 그러나 Matrix는 double을 사용하는 것으로 보이며 64 비트의 System.Double 정밀도는 다음을 사용해야합니다.

values ranging from negative 1.79769313486232e308 to positive 1.79769313486232e30

왜? 도움이 될만한 메시지를 보내 주셔서 감사합니다!


  • 답변 # 1

    행렬 클래스 DOES는 double을 사용합니다. 여기에서 소스 코드를 확인할 수 있습니다.

    public double Determinant
    {
        get
        {
            switch (_type)
            {
            case MatrixTypes.TRANSFORM_IS_IDENTITY:
            case MatrixTypes.TRANSFORM_IS_TRANSLATION:
                return 1.0;
            case MatrixTypes.TRANSFORM_IS_SCALING:
            case MatrixTypes.TRANSFORM_IS_SCALING | MatrixTypes.TRANSFORM_IS_TRANSLATION:
                return(_m11  * _m22);
            default:
                return(_m11  * _m22) - (_m12 * _m21);
            }
        }
    }
    
    

    (여기서 _m11 등은 모두 double 입니다. )

    다음 코드는 "동일 결과!"를 인쇄하여 계산과 Matrix.Determinant 간에 차이가 없음을 나타냅니다. :

    using System;
    namespace Demo
    {
        class Program
        {
            static void Main()
            {
                double m11 = 0.00000001, // 1E-08
                    m12 = 0,
                    m21 = 0,
                    m22 = 0.0000001; // 1E-07        
                double det = m11 * m22 - m12 * m21;
                Console.WriteLine(det);
                var mat = new System.Windows.Media.Matrix(m11, m12, m21, m22, 0, 0);
                Console.WriteLine(mat.Determinant);
                if (mat.Determinant == det)
                    Console.WriteLine("Same results!"); // This is printed.
                Console.WriteLine(mat.HasInverse); // Has no inverse, though.
            }
        }
    }
    
    

    HasInverse 의 구현을 보면 역수가 없다는 이유에 대한 대답 :

    public bool HasInverse
    {
        get
        {
            return !DoubleUtil.IsZero(Determinant);
        }
    }
    
    

    와이즈 비즈  따라서 구현됩니다 (현재 상황을보다 명확하게하기 위해 이것을 단순화했습니다) :

    DoubleUtil.IsZero()
    
    
    이 경우 public static bool IsZero(double value) { return Math.Abs(value) < 2.22044604925031E-15; }   value 입니다   1E-15 보다 적은  그래서 2.22044604925031E-15   DoubleUtil.IsZero() 를 반환  따라서 true   Matrix.HasInverse 를 반환 .

    false

  • 이전 php - 변수를 사용하여 다차원 배열을 만드는 방법
  • 다음 javascript - 아약스를 사용하여 간단한 문자열을 반환하는 웹 메서드