【问题标题】:different results in C and C# with Sin and Cos带有 Sin 和 Cos 的 C 和 C# 中的不同结果
【发布时间】:2014-06-24 09:18:37
【问题描述】:

我编写了一个程序来获取两个 gps 位置之间的角度。它在 C# 中运行良好,但在 C 中却不行。问题出在哪里?

这是C#中的代码

double lat1 = GetRAD(pos1.Latitude);
double lat2 = GetRAD(pos2.Latitude);
double long1 = GetRAD(pos1.Longitude);
double long2 = GetRAD(pos2.Longitude);

double angleAtCentre = Math.Acos(Math.Sin(lat1) * Math.Sin(lat2) + Math.Cos(lat1) * Math.Cos(lat2) * Math.Cos(long2 - long1));

double retVal = Math.Acos((Math.Sin(lat2) - Math.Sin(lat1) * Math.Cos(angleAtCentre)) / (Math.Cos(lat1) * Math.Sin(angleAtCentre)));
retVal = retVal * 180.0 / Math.PI;
if (long1 > long2)
{
    retVal = retVal * (-1);
}

return retVal;

这里是 C 中的代码

double lat1 = GetRAD(pos1.latitude);
double lat2 = GetRAD(pos2.latitude);
double long1 = GetRAD(pos1.longitude);
double long2 = GetRAD(pos2.longitude);

double angleAtCentre = acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(long2 - long1));

double retVal = acos((sin(lat2) - sin(lat1) * cos(angleAtCentre)) / (cos(lat1) * sin(angleAtCentre)));
retVal = GetDEG(retVal);
if(long1 > long2)
    {
    retVal = retVal * (-1);
}
return retVal;

我用坐标试了一下:Pos1 (47.0998194N, 9.8605694E), Pos2 (47.1004972N, 9.8600639E) C# 中的正确结果是 -26.9 度,在 C 中我得到类似 -88 的结果

【问题讨论】:

  • C语言中GetDEG函数的定义在哪里?
  • retVal = retVal * (-1); 应该是 retVal = -retVal;
  • 为什么只显示部分代码?错误很可能出现在您未显示的代码部分中。
  • 在 C 示例中显示 GetRadgetDEG 的定义。

标签: c# c trigonometry


【解决方案1】:

您将问题命名为:

C 和 C# 中带有 Sin 和 Cos 的不同结果

但是,您可以放心,两种语言的标准库函数都能正确执行三角函数。问题代码中的表达式在两个版本中是相同的。因此,差异行为必须来自度数/弧度转换函数,您省略了其代码。

-88-26.9 这两个值的比率为 3.27,与 π 非常接近。所以我的猜测是GetDEG 的 C 实现是不正确的。我怀疑你是这样写的:

deg = rad * 180.0;

但它必须是:

deg = rad * 180.0 / pi;

如果您包含math.h,那么您将能够将M_PI 用于π。或者如果您的math.h 没有定义M_PI,那么您可以自己定义它。你可以像这样编写度数/弧度转换函数:

double rad2deg(double rad)
{
    return rad * 180.0 / M_PI;
}

double deg2rad(double deg)
{
    return deg * M_PI / 180.0;
}

最后一条评论是,通常使用- 运算符的一元形式来对数字求反,而不是乘法:

retVal = -retVal;

这比您的代码读起来更清晰,并且与表达式的数学编写方式相匹配。

一个完整的演示程序在这里:

#include <stdio.h>
#include <math.h>

#define M_PI 3.1415926535897932384626433832795

double rad2deg(double rad)
{
    return rad * 180.0 / M_PI;
}

double deg2rad(double deg)
{
    return deg * M_PI / 180.0;
}

double angleBetween(double lat1, double long1, double lat2, double long2)
{
    double angleAtCentre = acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(long2 - long1));
    double retVal = acos((sin(lat2) - sin(lat1) * cos(angleAtCentre)) / (cos(lat1) * sin(angleAtCentre)));
    return long1 > long2 ? -retVal : retVal;
}

int main(void)
{
    double angle = angleBetween(
        deg2rad(47.0998194), deg2rad(9.8605694), 
        deg2rad(47.1004972), deg2rad(9.8600639)
    );
    printf("%f\n", rad2deg(angle));
}

输出

-26.915686

我建议你在你的系统上运行这个程序,亲自看看它是否提供了所需的输出。


更新

您在 cmets 中声称上述程序在您的系统上产生了输出 -92。如果确实如此,那么问题确实与您的系统有关。虽然,你的说法对我来说似乎有点牵强,但如果你的系统真的输出了那个值,那么它就坏了。

【讨论】:

  • 感谢您的快速答复。但我正确计算了 rad 值。我仍然有问题。值是否可能因为我在 Mikrokontrollerboard 上运行 C 代码而不同?也许与时钟频率?我尝试像这样切换位置:Pos1 (47.1004972N,9.8600639E), Pos2 (47.0998194N, 9.8605694E)。正确结果是 153 度,C 程序结果是 91
  • 我上面说的就是我要说的,直到你能提供完整的代码。我不明白你为什么寻求帮助然后隐瞒重要信息。你需要帮助吗?
  • 如果您真的怀疑您的 C 编译器,请在您的系统上运行我的答案中的程序。
  • 好的,抱歉。并再次感谢您的帮助。它似乎真的是 C 编译器。我尝试了您的代码,在以度数计算后得到-92。
  • 我的程序,在你的系统上运行没有改变,产生值-92?
【解决方案2】:

您的子程序错误。我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(void)
{
    double lat1 = 47.0998194 * 0.0174532925;
    double lat2 = 47.1004972 * 0.0174532925;
    double long1 = 9.8605694 * 0.0174532925;
    double long2 = 9.8600639 * 0.0174532925;

    double angleAtCentre = acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(long2 - long1));

    double retVal = acos((sin(lat2) - sin(lat1) * cos(angleAtCentre)) / (cos(lat1) * sin(angleAtCentre)));
    retVal = retVal * 180.0 / 3.1415;
    if(long1 > long2){
        retVal = retVal * (-1);
    }

    printf("value: %f\n", retVal);
}

0.0174532925 乘数用于将度数转换为弧度。和输出:

value: -26.916409

瞧……

下次您发布问题时,请确保包含您的子例程以及 pos1pos2 的结构。还假设您包括math.h

【讨论】:

  • 这是一个非常不寻常的 π 值
  • 这很有趣,但实际上您应该为 pi 使用适当的值,例如 M_PI。而且你不应该内联那些神奇的常量,使用辅助函数进行转换。我不是你的反对者,但在我看来这是有道理的。
  • 这是有道理的,只是复制粘贴似乎足以回答堆栈溢出问题..
  • 显然您回答中的基本思想是正确的。但是,您可以期望根据基本实践来判断。并且使用虚构的 π 值和注入魔法常数可能会招致反对。我想回答者应该表现出高标准的编码并遵循合理的做法,而不是马虎。我怀疑你真的在你的程序中使用3!由于M_PI 存在于math.h 中,因此可以使用。或者即使没有,您也可以在代码中写入PI 并允许询问者填写值。从语义上讲,这很清楚。
  • 请注意,这两个经度非常相似,因此减去它们会导致精度损失。这是球余弦定律的一个已知问题。首选半正弦公式。
猜你喜欢
  • 1970-01-01
  • 2021-05-07
  • 2015-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-05
  • 1970-01-01
相关资源
最近更新 更多