Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
228 views
in Technique[技术] by (71.8m points)

c++ - There is something wrong with my formulas and I can't figure out which one and where

#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;
            }
    }   
}

Here's the code first, sorry if it is very lengthy.

There is something wrong with my formula which I can't figure out what exactly, as it outputs near correct values when the angle input is a small number, and insanely wrong values when the angle input is something larger. Here's a screenshot of the outputs.

Screenshot of one session

You can see that when I input 20 and 60, it outputs near perfect answers. Using only Cos as an example, it outputs Cos = 0.9396926165 for 20 when the answer from Google is 0.93969262078, and Cos = 0.4999999106 for 60 when the answer from Google is 0.5. But when the numbers get big, like 300 and 340, the output values go insane as you can see from the screenshot.

Since it outputs the Sin and Cos values nearly correctly at lower inputs, I suspect that there is something wrong with my Power or Factorial functions.

Any ideas?

question from:https://stackoverflow.com/questions/65648369/there-is-something-wrong-with-my-formulas-and-i-cant-figure-out-which-one-and-w

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Your issue is with floating point error, mathematically your algorithm is correct, but your computer cannot hold big numbers with a sufficient precision. You're doing modulo 360, but that will put rad between 0 and 2*pi. That's too much.

What I would recommend is to "shift" your input, rad, between -pi and +pi. I tried the following and it works well :

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

If you prefer not to use std::floor you can also shift your angle in degrees between -180 and 180 with

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...