我需要计算任意向量的单位向量。线索是我不想引入浮点错误,所以我不能使用sqrt()函数。为了进行算术运算并且不引入浮点错误,我使用Rational数据类型。
public class Vector3
{
public Rational X { get; set; }
public Rational Y { get; set; }
public Rational Z { get; set; }
public Vector3(Rational x, Rational y, Rational z)
{
X = x;
Y = y;
Z = z;
}
.....
我的矢量单位计算如下:
public Vector3 Unit()
{
if (this.Length() == 0)
return new Vector3(0, 0, 0);
return this.DividedBy(this.Length());
}
public Rational Length()
{
return Sqrt(Dot(this).ToDouble());
}
public Rational Dot(Vector3 a)
{
return this.X * a.X + this.Y * a.Y + this.Z * a.Z;
}
问题是Sqrt()方法,因为我必须将我的Rational转换为double。而且,Sqrt()产生无理数。所以我在输入和sqrt函数的输出中可能出现舍入错误。
所以我需要计算没有平方根的向量的长度。这可能吗?
答案 0 :(得分:2)
不幸的是,你不能在这里做你想做的事,因为平方根通常(并且很有名)是不合理的。
如果你想坚持使用精确的算术,你可以通过保持你的高阶值来处理它,在一种扩展的有理数据结构中 - 一种代数几何事物。这条路径有其局限性,因为结果的多项式阶数通常是参数阶数的总和......
我认为CGAL提供了类似这样的选项。无论如何,如果您对几何数学感兴趣,但担心浮点错误,那么看看CGAL应该是一种教育。
答案 1 :(得分:1)
抱歉,没有平方根就无法完成。你对完善错误的担心被夸大了。
你可以用最小化错误的方式进行计算,比如这样(Java-ish语法; JDK中没有这样的Math.max,但是你明白了):
public double magnitude(double x, double y, double z) {
double maxComponent = Math.max(Math.abs(x), Math.abs(y), Math.abs(z));
double rx = x/maxComponent;
double ry = y/maxComponent;
double rz = z/maxComponent;
return maxComponent*Math.sqrt(rx*rx + ry*ry + rz*rz);
}
答案 2 :(得分:1)
如果您要解决的问题是对浮点错误敏感(我之前已经处理过一些问题),您是否有可能指定您愿意接受的容忍程度?例如,将其设置为输入数据集的精度?
假设这是可能的,我的建议是用一个已知准确达到一定容差的近似值替换sqrt(x)调用。
例如,您可以将其近似为寻根问题X ^ 2 - S = 0的解决方案。鉴于函数严格增加并且在正半平面上表现良好,您可以实现说二分或Newton-Raphson方法并根据公差终止它。
希望你发现它有用,即使它不能解决你的问题。
答案 3 :(得分:0)
有时可以删除sqrt:
对于通常需要单位向量的向量函数,有时可以通过一些聪明的数学来绕过sqrt。矢量投影就是一个很好的例子。
使用sqrt:
将向量a投影到向量b上将矢量a投影到不带sqrt的矢量b上:
额外的点(a,b)消除了对sqrt的需要。 但是花费3倍和2倍(对于矢量3)所以它不是免费的。