c++ - 我发现错误的结果是由于浮点精度吗?
问题描述
我正在尝试实现一个 GJK 算法,该算法应该返回两个凸形之间的距离,在未来我计划将其用于连续碰撞检测。在计算中,我使用浮点数来加快计算时间并使用更少的内存。我知道浮点数不是很精确,例如我经常得到 1...10-6 而不是 0,这并不太令人惊讶。然而,GJK 作为完成条件,类似于 [value <= error] 并且如果我选择低于 0.01 GJK 的值错误永远不会结束。从数学上讲,我应该得到 0,所以这意味着我已经累积了高达 0.01 的浮点错误,这可能吗?确实,我所做的计算非常大,我进行矩阵求逆和乘法运算,然后计算行列式并将它们相除。在下面的代码中,我展示了完成大部分计算的两个函数。如果这是一个精确问题,我该如何解决?虽然我真的不需要超过 0.1 的精度,但我仍然认为这有点奇怪。我还要补充一点,这个算法打印出看起来正确的值并正确检测到碰撞,所以这主要是为什么我认为这是一个精度问题,即使我有疑问。
//this code calls the calculations, as you can see there are some Matrix calculations here.
void ConvexShape::getDistance(const Matrix4x4& t1, const ConvexShape& shape, const Matrix4x4& t2)
{
Matrix4x4 rt1 = t1;
rt1.get(0,3) = 0.0;
rt1.get(1,3) = 0.0;
rt1.get(2,3) = 0.0;
Matrix4x4 rt2 = t2;
rt2.get(0,3) = 0.0;
rt2.get(1,3) = 0.0;
rt2.get(2,3) = 0.0;
Matrix4x4 invRT1 = rt1.invert();
Matrix4x4 invRT2 = rt2.invert();
Vector3 v = t1*support(invRT1*Vector3(1,0,0)) - t2*shape.support(invRT2*Vector3(-1,0,0));
Simplex simplex;
SupportVertex w(t1*support(invRT1*(-v)), t2*shape.support(invRT2*(v)));
while(v.dot(v) - v.dot(w.getMdPosition()) > 0.01)
{
simplex.addPoint(w);
v = simplex.getNearZero().getMdPosition();
w = SupportVertex(t1*support(invRT1*(-v)), t2*shape.support(invRT2*(v)));
}
std::cout << "DISTANCE = " << v.getLength() << std::endl;
}
//this a piece of code that calculated the barycentric coordonated of a thetrahedron it is often used.
void Simplex::getBarycentricCoordonates(const Vector3& OA, const Vector3& OB, const Vector3& OC, const Vector3& OD, float* u, float* v, float* w, float* k)
{
Vector3 AB = OB - OA;
Vector3 AC = OC - OA;
Vector3 AD = OD - OA;
Vector3 AO = -OA;
float ABAB = AB.dot(AB);
float ACAC = AC.dot(AC);
float ADAD = AD.dot(AD);
float ABAC = AB.dot(AC);
float ABAD = AB.dot(AD);
float ACAD = AC.dot(AD);
float AOAB = AO.dot(AB);
float AOAC = AO.dot(AC);
float AOAD = AO.dot(AD);
float detA = - ABAB*(ACAC*ADAD - ACAD*ACAD)
+ ABAC*(ABAC*ADAD - ACAD*ABAD)
- ABAD*(ABAC*ACAD - ACAC*ABAD);
float detAv = - AOAB*(ACAC*ADAD - ACAD*ACAD)
+ AOAC*(ABAC*ADAD - ACAD*ABAD)
- AOAD*(ABAC*ACAD - ACAC*ABAD);
float detAw = - ABAB*(AOAC*ADAD - AOAD*ACAD)
+ ABAC*(AOAB*ADAD - AOAD*ABAD)
- ABAD*(AOAB*ACAD - AOAC*ABAD);
float detAk = - ABAB*(ACAC*AOAD - ACAD*AOAC)
+ ABAC*(ABAC*AOAD - ACAD*AOAB)
- ABAD*(ABAC*AOAC - ACAC*AOAB);
float denom = 1.0/detA;
*v = detAv*denom;
*w = detAw*denom;
*k = detAk*denom;
*u = 1.0 - *v - *w - *k;
}
解决方案
推荐阅读
- reactjs - 我的消息消失了 我收到一条新消息或发送消息
- git - Flutter升级:ProcessException:进程异常退出
- html - 如何摆脱移动设备上烦人的 y 移动和滚动条?
- java - 一个外键用于相同类型的多个关系休眠
- vscode-extensions - 单击查看容器后执行操作
- python - Python unittest - 在同一测试中显示所有 AssertionError
- geometry - 具有最小平均绝对偏差的凸抛物线支持点?
- firebase - jetified-protobuf-javalite-3.14.0 com.google.protobuf:protobuf-javalite:3.14.0) jetified-protobuf-lite-3.0.1 (com.google.protobuf:protobuf-lite:3.0.1
- ruby-on-rails - Rubymine command + click 显示 Rails 方法,但不是 ruby 方法。是否可以在 Rails 应用程序中命令 + 单击 Ruby 方法?
- javascript - 我的js可以访问浏览器anc的唯一ID吗?