【问题标题】:There is something wrong with my formulas and I can't figure out which one and where我的公式有问题,我不知道是哪一个以及在哪里
【发布时间】:2021-01-09 22:45:18
【问题描述】:
#include <iostream>
#include <iomanip>
using namespace std;

//Power function
float power (float base, int exp)
{
    if (exp < 0)
        return 1 / (base * power(base, (-exp) - 1));
    
    if (exp == 0)
        return 1;

    if (exp == 1)
        return base;

    return base * power (base, exp - 1);
}

//Factorial function
int facto (int n)
{
    return n <= 0 ? 1 : n * facto (n - 1);
}

//Cos function
float cosCalc (float rad, int precision)
{
    float cos = 0;

    int x;
    for (x = 0; x < precision; x++)
        {
            cos += power (-1, x) * power (rad, x * 2) / facto (x * 2);
        }

    return cos;
}

//Sin function
float sinCalc (float rad, int precision)
{
    float sin = 0;

    int x;
    for (x = 0; x < precision; x++)
        {
            sin += power (-1, x) * power (rad, 1 + (x * 2)) / facto (1 + (x * 2));
        }

    return sin;
}

//Main function
int main()
{
    int precision = 10;
    int choice;

    //Title and Menu
    //Omitted this part cause it's irrelevant//

    while (true)
    {
        //User Prompt
        cout << endl << "Please enter your choice. => ";
        cin >> choice;
        
        if (choice != 1 && choice != 8 && choice !=9)
            {
                cout << endl << "Please enter a value between 1, 8 and 9.";
            }

        if (choice == 1)
            {
                int angle, anglePh;
                float rad;
                float pi = 3.14159265358979323846264338327950288419716;
                char angleType;
                float cos = 0;
                float sin = 0;

                cout << endl << "Please enter an angle. => ";
                cin >> angle;
                anglePh = angle;
                //To ensure that the angle given by the user is lower than 360 degrees
                angle %= 360;
                rad = angle * pi / 180;
                cout << anglePh << " degrees = " << rad << " radian";
                cout << endl << "Calculating Cos...";
                cos = cosCalc (rad, precision);
                cout << endl << "Cos = " << fixed << setprecision(precision) << cos;
                cout << endl << "Calculating Sin...";
                sin = sinCalc (rad, precision);
                cout << endl << "Sin = " << fixed << setprecision(precision) << sin;
            }
        
        if (choice == 8)
            {
                //Allows user to change the precision
            }

        if (choice == 9)
            {
                break;
            }
    }   
}

这是代码,如果很长,请见谅。

我的公式有问题,我无法弄清楚究竟是什么,因为当角度输入较小时,它输出接近正确的值,而当角度输入较大时,它会输出非常错误的值。这是输出的屏幕截图。

您可以看到,当我输入 20 和 60 时,它会输出近乎完美的答案。仅以 Cos 为例,当 Google 的答案为 0.93969262078 时输出 20 的 Cos = 0.9396926165,当 Google 的答案为 0.5 时输出 60 的 Cos = 0.4999999106。但是当数字变大时,比如 300 和 340,输出值就会变得疯狂,正如您从屏幕截图中看到的那样。

由于它在较低的输入下几乎正确地输出了 Sin 和 Cos 值,我怀疑我的 Power 或 Factorial 函数有问题。

有什么想法吗?

【问题讨论】:

  • 当您使用调试器运行此代码时,您看到了什么?这正是调试器的用途。如果您不知道如何使用它,这是一个学习在调试器中一次运行程序、监控所有变量及其变化时的值以及分析程序逻辑和执行的好机会。知道如何使用调试器是每个 C++ 开发人员必备的技能,没有例外。我们不会在 Stackoverflow 上调试其他人的代码,但在您的调试器的帮助下,您可以在不需要任何帮助的情况下找到此程序以及您编写的所有未来程序中的所有问题。
  • 浮点错误?
  • 您是否尝试过使用doubles 而不是floats?

标签: c++


【解决方案1】:

您的问题是浮点错误,在数学上您的算法是正确的,但您的计算机无法以足够的精度保存大数字。你正在做模 360,但这会将rad 放在02*pi 之间。太多了。

我建议在-pi+pi 之间“转换”您的输入rad。我尝试了以下方法,效果很好:

float cosCalc(float rad, int precision)
{
    float cos = 0;
    rad -= std::floor((rad + pi) / (2 * pi)) * (2 * pi); //< HERE 
    ...
}

如果你不想使用std::floor,你也可以在 -180 到 180 之间改变角度

angle = (angle + 180) % 360 - 180;

【讨论】:

  • 感谢您的帮助,但我忘了提到我不应该为此使用任何数学库,因此 floor 函数不起作用。你能解释一下改变我的输入背后的想法吗?为什么你的公式将 rad 放在 -pi 和 +pi 之间?我是一名新的计算机科学专业学生,所以我对所有这些概念还是陌生的。再次感谢您的帮助。
  • std::floor 可以通过强制转换为 int 手动完成
  • 嗨,我编辑了我的答案。您可以直接在角度上执行此操作(以度为单位),但这意味着如果您给 rad 太大,该功能将失败。
  • 或者将你的 double 转换为 long int(如果允许,也可以转换为 int64_t)
  • 参见Quimby's answer:除非您在泰勒近似中使用足够高的度数,否则误差会增长得非常快。您仍然可以使用我使用的公式,但转换为 int 或 long int 而不是使用 std::floor (如果允许)
【解决方案2】:

这是意料之中的,因为您知道距离泰勒级数的中心越远,它的精确度就越低。由于您将其扩展为 0,因此给它更大的角度将需要多次迭代才能获得正确的结果。

Wikipedia 对此有很好的了解:

在您的情况下,我建议使用关于这两个功能的已知测角规则并将自己限制在例如[-pi/4,pi/4]。 此外,对于更高的 x 值,您的公式将很快低于/溢出,您使用霍纳的方法来简化其评估。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-13
    • 2022-06-18
    • 1970-01-01
    • 2015-07-14
    相关资源
    最近更新 更多