我非常清楚从度到弧度的转换是如何工作的,但我仍然有问题。问题在于它的准确性。
您可能知道System.Math
库中的三角函数使用弧度,但我需要三角函数,您可以在其中插入度数。所以我创建了一个具有Cos
、Sin
和Tan
函数的Helper
类,这些函数只是将度数转换为它们内部的弧度并调用它们的Math
函数。
public static class Helper
{
public static double Sin(double degrees) => Math.Sin(degrees * Math.PI / 180.0);
public static double Cos(double degrees) => Math.Cos(degrees * Math.PI / 180.0);
public static double Tan(double degrees) => Math.Tan(degrees * Math.PI / 180.0);
}
但是,例如,当我使用Math.Tan(45)
时,它返回 0.999999999989 而不是 1。我的朋友们,我要问你们的问题是,如何使这句话完全准确。
提前谢谢。
编辑: 我知道,会有小错误,不可能摆脱它们。我真正想知道的是如何将值四舍五入所需的金额(不要太多,也不要太少(,以便无论如何它都可以工作。
编辑2: 上下文在这个问题上非常重要,所以这里是:
我需要为具有以下构造函数的Line
类进行三角函数:
public Line(Vector2 beginning, Vector2 end)
{
this.beginning = beginning;
this.end = end;
this.direction = 180.0 * Math.Atan(end.Y - beginning.Y / end.X - beginning.X) / Math.PI;
this.slope = Helper.Tan(direction);
this.length = Helper.DistanceBetweenTwoPoints(beginning, end);
this.offset = beginning.X;
}
问题出现在我为斜率分配值的线上,我需要使用线性代数检查点是否在这条线上。
披露:Vector2
是一个具有double x
和double y
的结构。就这样。
使用双精度时,您总是会遇到舍入错误。这就是浮点运算的本质。Double 可以携带大约 16 个十进制数字。在每个操作中,错误都会累积。"诀窍"是接受这个错误,永远不要将双精度/浮点数与相等进行比较(除非您知道自己在做什么(,并对输出进行有意义的四舍五入。
请参阅 http://floating-point-gui.de/。
要确定一个点是否位于两点之间的直线上或类似问题,您不需要四舍五入,而是使用公差:计算点和线之间的最短距离,并检查它是否低于阈值。这个阈值可以/应该有多大取决于您的应用程序,没有简单的答案。例如,如果您的点在 0..10 范围内,则 1e-7 的公差对我来说是合理的。如果你想要一个通用的实现,你应该采取最大的
- 点的距离乘以一个因子(例如
dist(begin, end) * 1e-8
( - 非常小距离的绝对值(例如
1e-10
(
但是您仍然会遇到问题。例如,如果线路从(10000000.1,0)
到(10000000.2,0)
,请参阅此处了解详细信息。一般来说,这是一个广泛的话题。
使用您通过Helper.Tan(direction)
获得的斜率来计算一个点是否在一条线上,对于不同的斜率会产生不同数量的误差,随着方向接近+/- PI / 2
,这些误差会变得更糟,因为随着x
接近+/- PI/2
tan(x)
接近无穷大,并且在+/- PI/2
时它根本不会起作用。
要查看点是否靠近线,请使用线的向量和到该点的向量的叉积。例如,线是从点A
到B
点,点是P
那么当P
在线时Cross(B-A,P-A)
将为零。为了消除与线长相关的误差,将叉积除以线长平方,并与任意小公差epsilon
进行比较。
// A,B, P are Vector2
double cross = (B.x-A.x) * (P.y-A.y) - (B.y-A.y) * (P.x-A.x);
cross /= (B.x-A.x) * (B.x-A.x) + (B.y-A.y) * (B.y-A.y);
double epsilon = 1.0e-6; // 1 millionths of a unit
if (Math.abs(cross) < epsilon) {
// point P is on line A,B
}
顺便说一句,Math.PI 是无理数的近似值,无论您使用什么系统,使用它都会引入错误。PI根本不能写成数字。在现实世界中,所有测量都有误差,对于PI 7位的所有实际应用,3.141592的精度绰绰有余。