簡體   English   中英

System.Windows.Media.Matrix不使用System.Double精度64位數字?

[英]System.Windows.Media.Matrix does not use System.Double precision 64-bit number?

我試圖使用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.'

但是在第二種情況下,我們可以看到(盡管矩陣檢查它是平方的並且其行列式不同於零),HasInverse為false,而Invert可能引發異常。 在這里,我可以看到的唯一區別是計算1E-15所需的精度。 但是Matrix似乎使用double和System.Double在64位精度應該使用:

值范圍從負1.79769313486232e308到正1.79769313486232e30

所以為什么 ? 感謝您提供的任何信息!

矩陣類使用雙精度型。 您可以在此處查看源代碼。

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

下面的代碼顯示“ Same results!”,表明您的計算與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的實現,可以找到關於為什么沒有逆的HasInverse

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

這樣實現了DoubleUtil.IsZero()位置(我已對此進行了簡化,以使其變得更加明顯):

public static bool IsZero(double value)
{
    return Math.Abs(value) < 2.22044604925031E-15;
}

在這種情況下, value1E-15 ,它小於2.22044604925031E-15因此DoubleUtil.IsZero()返回true ,因此Matrix.HasInverse返回false

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM