我在“ Ray Tracer挑战”中苦苦挣扎,在第4章中遇到了一个我无法超越的测试案例。

Scenario: Rotating a point around the x axis
  Given p ← point(0, 1, 0)
    And half_quarter ← rotation_x(π / 4)
    And full_quarter ← rotation_x(π / 2)
  Then half_quarter * p = point(0, √2/2, √2/2)
    And full_quarter * p = point(0, 0, 1)


第一个断言(half_quarter)可以正常工作,但是第二个断言(full_quarter)失败。


  预期Matrix.Multiply(full_quarter,p)等于(0,0,1,1),但找到(0,6.12323399573677E-17,1,1)。'


我的rotation_x实现如下:

        public static double[,] rotation_x(double radians)
        {
            var cos = Math.Cos(radians);
            var sin = Math.Sin(radians);

            return new[,]
            {
                { 1,   0,    0, 0 },
                { 0, cos, -sin, 0 },
                { 0, sin,  cos, 0 },
                { 0,   0,    0, 1 }
            });
        }


这是我的乘法方法:

        public static double[] Multiply(double[,] a, (double x, double y, double z, double w) b)
        {
            var product = new double[4];

            for (var r = 0; r < 4; r++)
            {
                product[r] = a[r, 0] * b.x
                           + a[r, 1] * b.y
                           + a[r, 2] * b.z
                           + a[r, 3] * b.w
                           ;
            }

            return product;
        }


在前面的章节中,我有很多关于矩阵和向量乘法的测试案例,因此,我很确定该部分可以正常工作。但是还有什么可能是错的?

最佳答案

您正在传递π的某个值,但Math.PI不完全等于π。它大约等于π,在17个有效数字以内。

正好π的正弦正好为零。非常接近π的正弦值非常接近零。您得到的是:6 x 10-17几乎接近零。

同样,π/ 2的余弦值恰好为零,但您传入的π/ 2的值仅精确到17位,因此结果仅精确到17位。

同样,Sqrt(2.0)/2.0也不完全是√2/ 2。近似值精确到约17个小数位。

系统中每个不是整数的数字都只能在17个小数位内正确,因此这里没有奥秘。您的结果正确到小数点后17位,因为您的输入正确到小数点后17位。您只能得到与输入一样多的精度。双精度不是无限精度!

(顺便说一下,很好地使用元组类型-但考虑使结构代表这些概念中的某些;这样,您可以将与这些概念相关联的方法放入结构中。)

关于c# - 矩阵变换,绕x轴旋转,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57699845/

10-15 06:50