C# 从度到弧度的转换不够精确

C# 从度到弧度的转换不够精确,c#,trigonometry,C#,Trigonometry,我非常清楚从度到弧度的转换是如何工作的,但我仍然有一个问题。问题在于它的准确性 正如您可能从System.Math库中了解到的,三角函数使用弧度,但我需要三角函数,在其中插入度数。因此,我创建了一个带有Cos、Sin和Tan函数的Helper类,它只需将它们内部的度转换为弧度,并调用它们的Math函数 public static class Helper { public static double Sin(double degrees) => Math.Sin(degrees *

我非常清楚从度到弧度的转换是如何工作的,但我仍然有一个问题。问题在于它的准确性

正如您可能从
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.999999989而不是1。我的朋友们,我想问你们的问题是,如何使这一点完全准确

提前谢谢

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

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

我的
类需要三角函数,该类具有以下构造函数:

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
是一种具有
双x
双y
的结构。仅此而已。

使用双精度时,您将始终存在舍入错误。这就是浮点运算的本质。Double可以携带大约16位十进制数字。每次操作错误都会累加起来。“诀窍”是接受这个错误,永远不要将double/float与equality进行比较(除非您知道自己在做什么),并对输出进行有意义的舍入

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

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

但你仍然会遇到问题。例如,如果行从
(10000000.1,0)
(10000000.2,0)
,请参阅以了解详细信息。一般来说,这是一个广泛的话题。

使用双精度时,总是会出现舍入错误。这就是浮点运算的本质。Double可以携带大约16位十进制数字。每次操作错误都会累加起来。“诀窍”是接受这个错误,永远不要将double/float与equality进行比较(除非您知道自己在做什么),并对输出进行有意义的舍入

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

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

但你仍然会遇到问题。例如,如果行从
(10000000.1,0)
(10000000.2,0)
,请参阅以了解详细信息。这通常是一个宽泛的主题。

使用通过
Helper.Tan(方向)
获得的斜率来计算点是否在直线上,对于不同的斜率会产生不同的误差量,随着方向接近
+/-PI/2
而变得更糟,因为
Tan(x)当
x
接近
+/-PI/2
时,
接近无穷大,而在
+/-PI/2
时,它根本不起作用

若要查看点是否靠近直线,请使用直线向量与指向该点的向量的叉积。例如,线是从点
A
B
的,点是
P
,然后
交叉(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
} 
/A、B、P是向量2
双交叉=(B.x-A.x)*(P.y-A.y)-(B.y-A.y)*(P.x-A.x);
交叉/=(B.x-A.x)*(B.x-A.x)+(B.y-A.y)*(B.y-A.y);
双ε=1.0e-6;//百万分之一单位
if(数学绝对值(交叉)

顺便说一句,Math.PI是无理数的近似值,无论使用什么系统,使用它都会引入错误。PI根本不能写成一个数字。在现实世界中,所有测量都有误差,对于所有实际应用,PI 7位数字3.141592的精度已经足够了

使用通过
Helper.Tan(方向)
获得的斜率来计算点是否在一条线上,对于不同的斜率会产生不同的误差量,随着方向接近
+/-PI/2
而变得更糟,因为
Tan(x)当
x
接近
+/-PI/2
时,
接近无穷大,而在
+/-PI/2
时,它根本不起作用

若要查看点是否靠近直线,请使用直线向量与指向该点的向量的叉积。例如,直线从点
A
B
,点是
P
,然后是
Cro