1.6.9浮点错误
关于在计算机上处理媒介的问题,我们应该了解以下内容。 在比较浮点数时,由于浮点不精确,必须小心。 我们预计相同的两个浮点数可能略有不同。 例如,在数学上,我们希望归一化矢量的长度为1,但在计算机程序中,长度将只是大约1.此外,对于任何实数p,数学上1p = 1,但是当我们只 有1的数值近似,我们看到提升到p次幂的近似值增加了误差; 因此,数值误差也会累积。 以下简短的程序说明了这些想法:
#include <windows.h> // for XMVerifyCPUSupport
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include <iostream>
using namespace std;
using namespace DirectX;
using namespace DirectX::PackedVector;
int main()
{
cout.precision(8);
// Check support for SSE2 (Pentium4, AMD K8, and above).
if (!XMVerifyCPUSupport())
{
cout << "directx math not supported" << endl;
return 0;
}
XMVECTOR u = XMVectorSet(1.0f, 1.0f, 1.0f, 0.0f);
XMVECTOR n = XMVector3Normalize(u);
float LU = XMVectorGetX(XMVector3Length(n));
// Mathematically, the length should be 1. Is it numerically?
cout << LU << endl;
if (LU == 1.0f)
cout << "Length 1" << endl;
else
cout << "Length not 1" << endl;
// Raising 1 to any power should still be 1. Is it?
float powLU = powf(LU, 1.0e6f);
cout << "LU^(10^6) = " << powLU << endl;
}
为了弥补浮点不精确性,我们测试两个浮点数是否近似相等。 我们通过定义一个Epsilon常量来做到这一点,这是一个非常小的值,我们用它作为“缓冲区”。如果它们的距离小于Epsilon,我们说两个值大致相等。 换句话说,Epsilon为我们提供了浮点不精确度的一些容差。 以下函数说明Epsilon如何用于测试两个浮点值是否相等:
const float Epsilon = 0.001f;
bool Equals(float lhs, float rhs)
{
// Is the distance between lhs and rhs less thanEPSILON?
return fabs(lhs - rhs) < Epsilon ? true : false;
}
当测试具有允许公差Epsilon参数的矢量的相等性时,DirectX Math库提供了XMVector3NearEqual函数:
// Returns
// abs(U.x – V.x) <= Epsilon.x &&
// abs(U.y – V.y) <= Epsilon.y &&
// abs(U.z – V.z) <= Epsilon.z
XMFINLINE bool XM_CALLCONV XMVector3NearEqual(
FXMVECTOR U,
FXMVECTOR V,
FXMVECTOR Epsilon);