从度数到弧度的转换不够准确

时间:2017-08-23 09:23:52

标签: c# trigonometry

我非常清楚如何从度数转换为弧度,但我仍然遇到问题。问题在于它的准确性。

你可能知道System.Math库中的三角函数使用弧度,但我需要三角函数,你可以在其中插入度数。因此,我创建了一个Helper类,其中包含CosSinTan函数,这些函数只会将度数转换为其中的弧度并调用其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而不是一个。我的朋友们,我向你提出的问题是如何使这一点完全准确。

提前致谢。

编辑: 我明白,会有一些小错误,也无法摆脱它们。我真正想知道的是如何将价值四舍五入所需的数量(不要太多,不要太少),这样它无论如何都会有效。

EDIT2: 上下文在这个问题中非常重要,所以这里是:

我需要具有以下构造函数的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 xdouble y的结构。这就是全部。

2 个答案:

答案 0 :(得分:3)

使用双打时,您将始终存在舍入错误。这就是浮点算术的本质。 Double可以携带大约16位十进制数字。并且在每次操作时,错误都会增加。 “技巧”是接受这个错误,永远不要将双打/浮点数与平等进行比较(除非你知道你在做什么)并对输出进行有意义的舍入。

请参阅http://floating-point-gui.de/

要确定某点是否位于两点或类似问题之间的一条线上,您不需要舍入但使用公差:计算点与线之间的最短距离并检查它是否低于阈值。这个阈值可以/应该有多大取决于你的应用程序,没有简单的答案。例如,如果您的点数在0..10范围内,则1e-7的容差对我来说是合理的。如果您想要通用实现,则应该采用最大值

  • 点的距离乘以因子(例如dist(begin, end) * 1e-8
  • 非常小的距离的绝对值(例如1e-10

但你仍然可能遇到问题。例如,如果您的行从(10000000.1,0)转到(10000000.2,0),请参阅here了解详细信息。这是一个广泛的主题。

答案 1 :(得分:0)

使用通过Helper.Tan(direction)得到的斜率来计算一个点是否在一条线上会对不同的斜率产生不同的误差量,当方向接近+/- PI / 2时会变得更糟,因为{当tan(x)接近x时会{1}}接近无穷大,而+/- PI/2接近+/- PI/2它将无法正常工作。

要查看某个点是否在某一行附近,请使用该行的向量和该向量的向量的叉积。例如,该行从点AB,当P在线上时,点为Cross(B-A,P-A),然后P将为零。为了解决与线长相关的误差,将叉积除以线长平方并与任意小的公差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
} 

BTW Math.PI是无理数的近似值,无论您使用何种系统,它都会引入错误。 PI根本不能写成数字。在现实世界中,所有测量都有误差,对于PI 7数字3.141592的所有实际应用都具有足够的精度。