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

时间:2018-01-23 13:24:27

标签: c# .net

我尝试使用System.Windows.Media中的Matrix,但我找到了一个我不明白的限制。

案例1:

 Array
(
    [0] => Array
        (
            [allocation_date] => 2018-01-01
            [t_project] => 10001
            [t_assign_to] => G2E0357
            [t_start_time] => 01:30 PM
            [t_end_time] => 11:30 AM
        )

    [1] => Array
        (
            [allocation_date] => 2018-01-02
            [t_project] => 10001
            [t_assign_to] => G2E0357
            [t_start_time] => 01:30 PM
            [t_end_time] => 11:30 AM

        )

    [2] => Array
        (
            [allocation_date] => 2018-01-03
            [t_project] => 10001
            [t_assign_to] => G2E0357
            [t_start_time] => 01:30 PM
            [t_end_time] => 11:30 AM
        )
)

在第一种情况下,我们看到:一切似乎都很好!

案例2:

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

但是在第二种情况下我们可以看到(尽管矩阵检查它是正方形并且它的行列式与零不同)HasInverse为false并且Invert可能抛出异常。在这里,我能看到的唯一区别是计算1E-15期间所需的精度。但是Matrix似乎使用了double和64位的System.Double精度应该使用:

  

值从负1.79769313486232e308到正数   1.79769313486232e30

为什么?感谢任何可能有帮助的消息!

1 个答案:

答案 0 :(得分:0)

矩阵类DOES使用双精度数。 You can check the source code here.

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 }}