我在“ 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/